Thursday, July 31, 2014

Rails Radio Button Form Helper or f.radio_button for short

There is an abundance of documentation out there for Ruby and Rails developers, in fact, I often have more trouble narrowing down my searches than finding no answer at all.  However, I also often find that the documentation assumes a level of understanding that a beginner doesn't have.  Recently I spent a couple of hours trying to figure out how to use the radio_button form helper.  There was tons of documentation about radio_button_tag, but not as much about radio_button and the parameters were slightly different.  So I decided to write a short beginners guide to f.radio_button.

Again, I’m a beginner myself so I hope you’ll excuse any misunderstandings and help me correct them.  I’m using Ruby 2.0.0p451 and Rails 4.1.0.

My example will be for a radio button that lets you select a level of recurrence: daily, weekly, monthly, none, and stores that choice, as a string in @meeting.recurrence which we’ll assume is set to “none” to start with.  First up, the basic structure of the helper:

<%= f.radio_button :yourfield, “thevalue”,{options: “withvalues”} %>

My actual implementation:

<%= f.radio_button :recurrence, “none”, {checked: “none”==@meeting.recurrence, onClick: “expand(‘none’)} %>

My form is set up as:

<%= form_for(@meeting) do |f| %>

so “f.” implicitly forces my field names to refer to @meeting.fieldname, so :recurrence is shorthand for: @meeting.recurrence.

The second parameter is the value I want the radio button control to return if this item is selected, so “none” is my result if this value is checked.

The third parameter is a hash of options.  In my case, I have two options that I pass to each button in the group of radio buttons. The first determines if the button is the one checked upon page paint.  It sets the parameter ‘checked‘ = true|false by comparing the data attribute to the selection value.  In this example: “none”.  So if @meeting.recurrence is equal to “none” we get true, if not, we get false.

The second parameter is a javascript function that I want called when this item is clicked.  The function is called ‘expand’ and takes a parameter that tells it which option was clicked, in this case, “none”.
This generates the following html code:

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />

Let’s break this down into is constituent parts:


  • Because @meeting.recurrence was equal to “none”, my checked option became “checked: true” which translates in the html to checked=”checked”.  
  • The id is derived from values in the call.  :recurrence (remember, this is short for @meeting.recurrence) becomes meeting_recurrence and then the value “none” gets concatenated to give us “meeting_recurrence_none”.  
  • The name similarly is derived from @meeting.recurrence and becomes meeting[recurrence].  Note that this field, the name, is common across all the buttons in your radio button group and is how the application knows they are part of the same set.
  • My onClick hander just gets passed in directly.
  • The type is implied by the radio_button helper.
  • Finally, the return value is set directly from the second parameter, the value.
Now we need to tell the user what this radio button is so we will pair it with a label.  This is the syntax for a label helper.

<%= f.label :yourfield, "thestring", :value => "thevalue" %>

And here is the actual implementation for the label that matches my radio button.

<%= f.label :recurrence, "none", :value => "none" %>

And the HTML that generates:

<label for="meeting_recurrence_none">none</label>

Again, you can see that :recurrence and the value become “meeting_recurrence_none”  which is how this label is tied to the radio button field by its ID.  This allows the label to be clickable as part of the radio selection.  The “thestring” parameter becomes the string shown to the user.

Now here is the whole block I set up for my four options in my radio button group complete with their labels.

<%= f.radio_button :recurrence, "daily", {checked: "daily" == @meeting.recurrence, onClick: "expand('daily')"} %>
<%= f.label :recurrence, "Daily", :value => "daily" %>

<%= f.radio_button :recurrence, "weekly", {checked: "weekly" == @meeting.recurrence, onClick: "expand('weekly')"} %>
<%= f.label :recurrence, "Weekly", :value => "weekly" %>

<%= f.radio_button :recurrence, "monthly", {checked: "monthly" == @meeting.recurrence, onClick: "expand('monthly')"} %>
<%= f.label :recurrence, "Monthly", :value => "monthly" %>

<%= f.radio_button :recurrence, "none", {checked: "none" == @meeting.recurrence, onClick: "expand('none')"} %>
<%= f.label :recurrence, "None", :value => "none" %>

This results in the following final block of HTML being rendered:

<input id="meeting_recurrence_daily" name="meeting[recurrence]" onClick="expand(&#39;daily&#39;)" type="radio" value="daily" />
<label for="meeting_recurrence_daily">Daily</label>

<input id="meeting_recurrence_weekly" name="meeting[recurrence]" onClick="expand(&#39;weekly&#39;)" type="radio" value="weekly" />
<label for="meeting_recurrence_weekly">Weekly</label>

<input id="meeting_recurrence_monthly" name="meeting[recurrence]" onClick="expand(&#39;monthly&#39;)" type="radio" value="monthly" />
<label for="meeting_recurrence_monthly">Monthly</label>

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />
<label for="meeting_recurrence_none">None</label>

Finally, to bring it home, this is the data that gets submitted to the server for this control:

"meeting"=>{"recurrence"=>"daily"}

I hope that some other beginner might find this just a little bit helpful.

Using Mandrill Send Template from Rails

Last time I posted I covered creating a method that can invoke the Mandrill API to send an e-mail message via a template. This time I'll cover how I actually used it.
First off, I used Mail Chimp to create our outbound messages. You need to create both a Mail Chimp account and a Mandrill account. Mail Chimp then allows you to link the two accounts together. Mail Chimp uses merge tags of the form: *|attribute_name|*. They are case insensitive and I used only letters and underscore in naming them.
Mail Chimp will include a few extra meta tags like if statements: *|IFNOT:ARCHIVE_PAGE|*and some common variable such as: *|LIST:COMPANY|*. The above if statement is used to alter content in the message when displaying a copy of it on a website instead of the recipient using their mail client directly. I opted not to implement that capability at this time so those tags get removed when I edit the message in Mandrill.
After saving the templates, use the Send To Mandrill option on the Edit button in Mail Chimp. This will create a copy of the template in Mandrill. At this time the GUI integration between Mail Chimp and Mandrill isn't very tight so you may have to create copies of templates and export them to Mandrill to do updates. I hope Mail Chimp will tighten this integration up soon.
Once the template is exported to Mandrill, switch over to your Mandrill account and edit the template. Remove the IF tags that I mentioned. Also, remove any other default tags that you don't want. I opted to keep the *|LIST:COMPANY|* tag, however, Mandrill doesn't recognize that tag format (another area I hope Mail Chimp will tighten up) so I replaced colons with underscores like: *|LIST_COMPANY|*. Note the template slug name. This is the name by which you will invoke this message.
Now we have a template that we are ready to send. Over in Ruby we need to invoke our sendtemplate method. So here it is: Again, sorry about the formatting, I don't think Linkedin intended for code examples to be included.
def sendtouser(user)
  subject = "Welcome and thank you for signing up!"
  mandrillsend = Mandrill::Mandrill.new
  result = mandrillsend.sendtemplate(
    "getting-started", # Mandril slug name
    Rails.configuration.returnaddress, # return email address
    Rails.configuration.returnname, # name to show for return
    user.email, # target email address
    user.full_name, # name to show for target
    subject, # Message subject
    [{"name" => "subject", "content" => subject},
      {"name" => "CURRENT_YEAR","content" => Time.now.year.to_s},
      {"name" => "LIST_COMPANY","content" => "My Company, LLC."},
      {"name" => "HTML_LIST_ADDRESS_HTML","content" => OfficeAddress},
      {"name" => "unsub","content" => Rails.application.routes.url_helpers.url_for(:host => Rails.configuration.serverroot, only_path: false, controller: "contacts", action: "unsub", id: encrypted_id)},
      {"name" => "UPDATE_PROFILE","content" => Rails.application.routes.url_helpers.url_for(:host => Rails.configuration.serverroot, only_path: false, controller: "users", action: "edit", id: user.id)}
    ]
  )
    
  Rails.logger.debug("--- manmailer.signed_up result")
  Rails.logger.debug(result.code)
  Rails.logger.debug(result.body)
  Rails.logger.debug("-------------------------------)
  
  status = result.code
  
  result_body = result.body
  
  return status.to_i == 200 # expect back 200 on the return code
end # sendtouser
All of the replacement variables are referenced by name (CURRENT_YEAR) in an array [] of name value pair hashes {}.
So you can see that {"name" => "CURRENT_YEAR","content" => Time.now.year.to_s} will result in the variable *| CURRENT_YEAR|* being replaced by the value generated by Time.now.year.to_s.
I hope this post, when coupled with my last post might help get a few folks integrating with Mandrill.