Austin Story

Ruby, Rails and Javascript Blog

Powered by Genesis

How to create a User and an Account in one form with Devise

November 22, 2015 By Austin Story Leave a Comment

Most of my apps these days that are pure html with a backend are written in Ruby on Rails and use the Devise engine to handle password and account creation type things.

For this example we will be assume a few things

  • You have rails 4+ and Devise Setup
  • Devise routes are setting the registration controller as your custom controller.
  • models are User and Account
  • User belongs_to Account (so User has an account_id)
  • User responds to set_admin to deal with however admin is setup.

I was reading through the source the other day and saw this block option in the RegistrationsController for devise

[ruby]

class Devise::RegistrationsController

# POST /resource
def create
build_resource(sign_up_params)
resource.save

yield resource if block_given?
#other devise stuff
respond_with resource
end
end
[/ruby]

 

[ruby]yield resource if block_given[/ruby]

means that we can pass some code in as a block (which is just an anonymous function) that will receive the resource as a parameter.

 

In your resources controller you can override like this

[ruby]

class RegistrationsController < Devise::RegistrationsController
def create
super {|user| user.create_account }
end
end

[/ruby]

So with this code, super sends the block up the chain.  So the result is that when we get to the yield resource, the resources receives the message ‘create_account’.

This is great, now we are able to delegate all of our registration logic to devise.  But wait, what if we now want to set the user as admin on the account and make sure that it is all wrapped up in a transaction?  That is easy, just expand the block.

[ruby]
def create
ActiveRecord::Base.transaction do
super do |user|
user.create_account
user.set_admin
end
end
end
[/ruby]

At this point, we have fulfilled the feature that we create the account along with the user and set that user as the admin on the account, so ship the feature!

Filed Under: Devise, Ruby, Ruby on Rails Tagged With: Devise, Rails, ruby, ruby on Rails, Ruby super

Ruby/Rails Metaprogramming – Creating a custom alerting module

April 19, 2015 By Austin Story Leave a Comment

I recently needed to be able to dispatch some very context specific alerts when some of my classes are saved. However, the alert and who gets it are completely different based on the class and the context of quite a bit of business logic. This could be accomplished is several ways, I will explain these and then show how i accomplished it with metaprogramming and modules.

The most straightforward way to have done this would be to just add an alert method in each class and then implement the logic there. There are several reasons to shy away from this including polluting your model, strong coupling and harder testing. However, I shy away from that because it promotes bad coding. Each time you tack on just one more method to a class it makes it that much easier to do it again. I’m not saying never just add a method, but think about whether it could be it’s own thing first.

The next would be to have a giant class that handle the logic. This would be better because all the logic for alerting in the app would be in one spot. However, the logic would have several branches (i.e is this a comment or an image or a new post?).

Ultimately i created an alertable module that I included in my models.

[ruby]module Alertable
extend ActiveSupport::Concern

included do
after_save :alert
end

def alert
"Alerts::#{self.class}".constantize.new(self).call
end

end

class Comment < ActiveRecord::Base
include alertable
end
[/ruby]

From the top, ActiveSupport::Concern gives me both class level methods (after_save) and instance methods (def alert). Pretty neat.

The alert method is a bit of metaprogramming that allows me to put the alert logic in it’s own module namespace (aka directory) like this

models/comments.rb #Normal ActiveRecord Model Location
models/alerts/comments.rb #our new Module

Because alertable is include in Comment, when a comment is saved it now does a callback for the method ‘alert’. That is also included from Alertable so after it sees that there are no alert methods defined in the Comment class it calls “Alerts::Comment”.constantize.new(self).call Which is located in models/alerts/comments.rb

The comments.rb file under models/alerts will look something like this.

[ruby]
module Alerts
class Comment
def initialize(comment)
@comment = comment
end

def call
#Do alerting stuff
end

end
end
[/ruby]

So now any time that i need to do some alerting in my program, i include Alertable and then i can either implement the alert method on the class i’m including it into or (preferably) create a new Alerts::#{class_name} file.

I think this setup is better than the 2 previously mentioned because everything that is related to alerting is not located in a single area of the application. The alerts are their own thing in their own area of the application. The downside is that we have callbacks for the Comment class that are completely encapsulated in a module. So that could cause trouble for newer programmers to the project or if the alert ever returns falsy it would halt the save of our comment and not be immediately apparent as to why it was failing.

Filed Under: Ruby, Ruby on Rails Tagged With: Metaprogramming, Modules, Rails, ruby

Understand how Ruby on Rails Dropdown Menus Work – Rails Select Tag and Options For Select

November 25, 2014 By Austin Story 4 Comments

I have programmed using rails for a while, but while helping with a Stackoverflow question i realized I didn’t have a very firm grasp of the interworkings of select_tag or options_for_select. So I wrote this blog post in order to get a better understanding of it.

Both of these tags are located in ActionView::Helpers and are used to turn some collection of stuff into an intelligently grouped options list that can be selected.

Rails provides several ways to do this ranging from simple to intimidating (meaning, you pass in 5 different options to a method and hope that the order is correct). The latter can be a little daunting for beginner developers and frustrating for more advanced developers who use the components only often enough to forget the order before the next time they use them.

To start with, let’s create a simple select box in html.

[ruby]
&amp;lt;select name="user_id" id="user_id"&amp;gt;
&amp;lt;/select&amp;gt;
[/ruby]

This html is the minimum you can generate with a select_tag call, you must supply either a name or symbol that is converted using ruby into the name=” and id=” above. The above select tag would look like this.

[ruby]
&amp;lt;%= select_tag(:user_id) %&amp;gt;
[/ruby]

Note that you cannot just call select_tag with no options. The element for the name/id is required.

Now that we have a select box that will submit a user_id in the form, we will want to put some options in the box. A quick and dirty way to accomplish this task is to add a string representing the options.

[ruby]
&amp;lt;%= select_tag(:user_id, '&amp;lt;option value="1"&amp;gt;Jemmy Legs&amp;lt;/option&amp;gt;&amp;lt;option value="2"&amp;gt;Talos&amp;lt;/option&amp;gt;') %&amp;gt;
[/ruby]

However, this string will not work. If you put this in a rails project it will display an empty dropdown box because select_tag is actually a facade for content_tag. The options in the second argument are passed to a call to content_tag in the helper. Content tag sends this to another helper which passes your content options to ERB::Util.unwrapped_html_escape.

So ultimately, it is escaped in a way where it is ‘safer’ before it leaves the server

To get it to work you can chain on the html_safe method method.

[ruby]
&amp;lt;%= select_tag(:user_id, '&amp;lt;option value="1"&amp;gt;Jemmy Legs&amp;lt;/option&amp;gt;&amp;lt;option value="2"&amp;gt;Talos&amp;lt;/option&amp;gt;'.html_safe) %&amp;gt;
[/ruby]

Now that we are creating getting a dropdown box, we will want an easier way to build the options. This can be accomplished using the method options_for_select to generate our options AND set them as html_safe without having to type out all the html.

The options_for_select arguments is a set of name and value pair represented by a hash, array, enumerable, or some other type. Below is a nested array demonstrating their format.

[
[‘textdisplayed in dropdown box’, ‘value_sent_to_server’],
[‘Jemmy Legs’, 1],
[‘Talos’, 2]
]

In action it looks like this

[ruby]
#just the options
&amp;lt;%= options_for_select([['Jemmy Legs', 1], ['Talos', 2]])%&amp;gt;

#combined together with select tag
&amp;lt;%= select_tag(:user_id, options_for_select([['Jemmy Legs', 1], ['Talos', 2]]))%&amp;gt;
[/ruby]

Options_for_select is located in ActionView::Helpers::FormOptionsHelper. If the object passed to it (the nested array, hash, etc) responds to .map and provides a text and value through option_text_and_value, then it calls the content_tag_string helper on each text-value pair, joins them with a new line and finally calls html_safe on the results.

My next blog I plan to dive deeper in the helpers mentioned above. Here are some good links in the meantime.

Good Links
Source
https://github.com/rails/rails/blob/7e375afba30951b60a3e606ccbfe3f28b0df5e1a/actionview/lib/action_view/helpers/form_tag_helper.rb

Rails Guides
http://guides.rubyonrails.org/form_helpers.html#making-select-boxes-with-ease

http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select

http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html

facade pattern
http://en.wikipedia.org/wiki/Facade_pattern

Filed Under: Ruby on Rails Tagged With: ActionView, Content Tag, Helpers, Options For Select, Rails, Select Tag, select_tag

  • 1
  • 2
  • Next Page »

Categories

  • AngularJS
  • Books
  • Devise
  • Elasticsearch
  • ES6
  • Information Security
  • Integrations
  • Javascript
  • Linux
  • Minitest
  • PhoneGap
  • Programming
  • React
  • Redux
  • Ruby
  • Ruby on Rails
  • Stripe
  • Testing
  • Theory
  • TypeScript
  • Uncategorized
  • Vue
  • Webpack