Collection Select Helper and OnChange Event in Rails

Given a collection of Active Record objects, you may use the collection_select helper method to produce a select form field. You need to pass in a number of arguments to the helper function.

1) object – your model object used in the collection
2) method – a valid model attribute or method
3) collection – a collection of active record model objects
4) option_value – value being set from the model for the <option value=”option_value”> html element
5) option_name – what is displayed for the user e.g., <option> option_name <
6) option – general options
7) options for the select html element

# helper and arguments...
# collection_select( model, id, collection, option_value, option_name, options, html_options)

&lt;%= collection_select("states", "state_id",
  State.participating,
  "abbreviation", "name",
   {:selected=&gt; get_current_state_or_nil },
   {:onchange=&gt;"document.location='/states/'+this.value"}
) %&gt;

#which will produce something like...

<pre id="line27">&lt;select id="state_id" name="state[id]" onchange="document.location='/states/'+this.value"&gt;
&lt;option value="AL"&gt;Alabama&lt;/option&gt;
&lt;option value="AK"&gt;Alaska&lt;/option&gt;
&lt;option value="AZ"&gt;Arizona&lt;/option&gt;
&lt;option value="AR"&gt;Arkansas&lt;/option&gt;
&lt;/select&gt;
26 Aug 2010, 8:44pm
ruby:
by

1 comment

Repost

This post is inspired by
http://pupeno.com/blog/really-resetting-the-database/#comment-1179
. But as my blog mostly serves as a reference for my future self, I’d like to reprint this little snippet of code here as well.

namespace :db do
  desc "Crush and burn the database"
  task :hard_reset => :environment do
    File.delete("db/schema.rb")
    Rake::Task["db:drop"].execute
    Rake::Task["db:create"].execute
    Rake::Task["db:migrate"].execute
    Rake::Task["db:seed"].execute
    if !Rails.env.test?
      Rake::Task["db:data"].execute
    end
  end

  desc "Generate sample data for developing"
  task :data => :environment do
    # Create the sample data in here
  end
end

Rounded Corners with CSS

.rounded_corners {
     -moz-border-radius: 20px;
    -webkit-border-radius: 20px;
    -khtml-border-radius: 20px;
    border-radius: 20px;
}

Select Distinct in Rails with Active Record

User.find :all, :select => "DISTINCT occupation"

A List of Every High School in the United States in Pipe Delimitted Form (2005)

Here is a text file containing every high school in the United States(2005), including city, state, zip code and high school name.

us_high_schools_pd

The Context of Markup vs Expressions of Equality in Determining the Meaning of Angled Brackets

In the WordPress editor (html mode) you’ll need to become friends with < and > if you plan on showing any code (php, html… xml, most languages actually) that readers will want to understand.

I never thought about it, but assumed that the lt and gt stood for left, and gt, well, i couldn’t quite place it, respectively. But alas, it dawned on me. Lt = less than while gt = greater than. Seems obvious now, but when you are thinking about angled brackets as markup, rather than as logic in an expression, the meaning that has value happens to be left vs. right.

Context is important.

Simple Activity Stream Implementation in Rails

There are many ways to tackle the Facebook style activity stream feature for your app. The simplest approach, which you can tack on at almost any moment, is what I’ll describe here. You don’t have to create a new model for news feed items or create any polymorphic associations. You simply query for the records on separate models you would like aggregated in the stream, and render a partial for that record, which Rails will map for you.

# in app/controllers/home_controller.rb
def index
 @activity_stream = (Forum.find(:all, :limit =&gt; 10, :conditions=&gt;["created_at &gt; ?", 1.day.ago]) + ForumPost.find(:all, :limit =&gt; 10)).sort_by {|item| - item.created_at.to_i}
end

The sort_by method at the end places all of your feed item into descending chronological order. Omit the minus sign and they will be sorted in ascending order.

sort_by {|item| - item.created_at.to_i} # in descending chronological order

Show your latest activity in your views…

#app/views/home/index.html.erb
&lt;%= render @activity_stream rescue nil %&gt;

This assumes that you will have created the partials for each resource using Rails conventions i.e., you have in created the partials for the models like so app/views/_[the model name].html.erb. In this instance, you should have app/views/forums/_forum.html.erb and app/views/forum_posts/_forum_post.html.erb

You can rename the partials to something like _stream_forum.html.erb, if you already have the forum partial gainfully employed. You’ll need to change the view and prob. throw it into a loop to either check for a condition or use _stream_[model name].html.erb as the convention for any stream items.

Scope Routes/URLs By Username (like Twitter) in Your Rails Application

There are a few things that need to be taken care of before you can get this to work. The first thing (although, any of the following steps can be done in any order) to take care of involves your User model. You need to override the to_param method, so that Rails will appropriately use the username attribute rather than user_id when constructing paths.

#in app/models/user.rb
def to_param
  "#{self.username}"
end

Next we move onto routing our resources. Here it gets a little tricky because Rails is building paths for us. Remeber, you can get a list of all currently defined routes in your application by running the routes rake task

rake routes

We need to set the path_prefix option on any of our resources we want scoped by the username. For instance, in this example, I have set up a Status model and statuses_controller, whose urls shall be scoped by the username. You can apply the path_prefix to any number of other resources in your routes config file. They symbol used is arbitrary, but will be made available in the params hash, in this case params[:user_id]. You also need to exclude the show action on your users resources declaration. The reason is that, otherwise, Rails will include the controller name in the path like /users/username, which doesn’t look as clean as just /username. You then need to redefine this route explicitly (last line in the routes config shown here).

#in app/config/routes.rb
map.resources :statuses,   :path_prefix =&gt; '/:user_id'
map.resources :users,     :except =&gt; [:show]
map.user '/:username' :controller =&gt; 'users', :action =&gt; 'show'

Finally, you get to call these routes in your views or use them in your controllers. You use the same link_to, url_for methods to generate paths. When constructing the resources you have setup with the path_prefix declartion, remember you need the user model as the first argument, followed by said resource.

&lt;%= link_to(status.title, status_path(status.user,status) %&gt;
# or in a controller
redirect_to status_path( status.user, status )

That’s pretty much it. If anyone has another way of doing this let me know!

Using Formtastic to Cleanly Create Nice Looking Forms in Rails

Forms can easily get cluttered when you’re dealing with a lot of form fields… er, ERB tags. I’ve written about extending Rails form builders, which certainly goes along way to shrinking your views where forms are used. The plugin Formtastic is even better, as it lets you skirt maintaining your own library in favor of a very, elegant DSL.

For a great overview of the plugin and implementation details, check out Ryan Bate’s Railscast. There are a couple episodes, but be sure to catch the first one, linked above.

I usually install the plugin as a gem

# config/environment.rb
#...
config.gem "formtastic"

and then run a generator to create the stylesheets for me, making forms look nice and neat.

./script/generate formtastic

One gotcha, is that in order for the css to render correctly you need to add this

&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;

in the head of your layout file.

You define forms usingĀ  “semantic_form_for” like so…

&lt;% semantic_form_for @user do |f| %&gt;
  &lt;% f.inputs do %&gt;
    &lt;%= f.input :login, :label =&gt; "Username", :hint =&gt; "Something short because it's in the url"%&gt;
  &lt;% end %&gt;
  &lt;%= f.buttons %&gt;
&lt;% end %&gt;

As per usual, there are a myriad of configuration options which can be overridden if necessary. Consult the documentation at Justin French’s Github account for specifics.

TODO and Custom Annotations in Rails Applications

While writing software it’s common to leave comments for your future self. For instance, if you have written some code but realize that it should be refactored to be more efficient, you may place something along the lines of “TODO: change active record find method and replace w/ a custom sql select finder “. With rails, if you follow this convention, you can get a list of your annotations with a rake task.

rake notes:todo

which will print out the file where the the todo was found along with the line number and the comment…

app/controllers/application_controller.rb:
  * [  8] fix me

Rails defines several other annotation types for you

rake notes                                # Enumerate all annotations
rake notes:fixme                          # Enumerate all FIXME annotations
rake notes:optimize                       # Enumerate all OPTIMIZE annotations
rake notes:todo                           # Enumerate all TODO annotations

And you also may define your own

# SEAN: please rewrite this method to query only chunky bacon

you may find all instances of “SEAN” by running

rake notes:custom ANNOTATION=SEAN