code tunes

Web applications, software engineering, Ruby on Rails, Cake PHP, JavaScript, etc.

Archive for the ‘Ruby on Rails’ tag

“Send this page to friend” with polymorphic controller in Rails

with one comment

Last week I wrote about Tableless models in Ruby on Rails, giving an example of Recommendation model which could be used to validate users’ recommendations. Today I will extend that example so that it will be more complete.

What the mentioned solution lacks is a controller handling recommendation actions. Let’s first make Article and Photo models recoommendable ones by defining their associations:

  has_many :recommendations, :as => :recommendable

The models are ready, so let’s create a controller.

class RecommendationsController < ApplicationController
  def new
    if !params[:photo_id].nil?
      @recommedable = Photo.find params[:photo_id]
    elsif !params[:article_id].nil?
      @recommedable = Article.find params[:article_id]
    end
 
    raise ActiveRecord::RecordNotFound if @recommendable.nil?
  end
 
  def create
    @recommendable = Recommendable.new :params[:recommendation]
 
    if @recommendable.valid?
      # send it via e-mail
      flash[:notice] = 'Your recommendations has been processed'
      redirect_to @recommendation.recommendable
    else
      render :action => :new
    end
  end
end

We’re almost there, but there’s more Rails can do for us here. Let’s define some new routes.

# config/routes.rb
  map.resources :recommendations
 
  map.resources :articles do |a|
    a.resources :recommendations
  end
 
  map.resources :photos do |p|
    p.resources :recommendations
  end

Now we’re able to use those pretty helpers in our views that will generate nice-looking URLs (like: article/1/recommendation/new).

<%= link_to 'recommend this article', new_article_recommendation_path(@article) %>

The link above will take us to the ‘new’ action of RecommendationsController. The last thing we need to do is to render the form, so that user can comment his recommendation.

<% form_for @recommendable.recommendations.build do |f| %>
  <%= f.hidden_field :recommendable_type, :value => @recommendable.class %>
  <%= f.hidden_field :recommendable_id, :value => @recommendable.id %>
  <%= f.text_field :email %>
  <%= f.text_area :body %>
  <%= f.submit 'Do it!' %>
<% end %>

There are many more cases of use polymorphic controllers (with normal or tableless models) than sending recommendations. Commenting, ranking, abuse-reporting, tagging… The rule is that if you have a model that is associated to other models via polymorphic association, you should consider using polymorpic controller to manage it. Not only Rails will do much work for you behind the scenes, but the structure of your application will stay clear both inside (reusable code) and outside (nice links).

Written by Michał Szajbe

July 26th, 2008 at 4:06 pm

Tableless models in Rails

with 3 comments

If you’re developing an application in Ruby on Rails framework, there are many situations when you should consider using tableless models. The advantages you’d get are:

  • consistent application structure, because you’re using models to represent objects in your app
  • routes available for free if you also define controllers dedicated for those models, resulting in RESTful application
  • easy validation (just like with normal models) and other goodies shipped with Active Record
  • easier testing with unit tests
  • form building as easy as with normal models

If you’re familiar with “fat model, skinny controller” concept you’ll find more reasons.

An example situation: you give the users an ability to recommends object they find on the site to their friends. They can recommend photos and articles. You do not want to track those recommendations in database. Your model file would look like this.

class Recommendation < ActiveRecord::Base
  class_inheritable_accessor :columns
  self.columns = []
 
  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
  end
 
  column :recommendable_type, :string
  column :recommendable_id, :integer
  column :email, :string
  column :body, :text
 
  belongs_to :recommendable, :polymorphic => true
 
  validates_presence_of :recommendable
  validates_associated :recommendable
  validates_format_of :email, :with => /^$|^\S+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,4})(\]?)$/ix
  validates_presence_of :body
end

As you can see the only difference in model definition is that you need to provide the columns yourself.

The idea was borrowed from this snippet.

In the next article I’ll cover polymorphic controllers which will help to convert above example into complete one.

[edit: Thanks to Curran Schiefelbein for making this work when tableless model is inherited by another model.]

Written by Michał Szajbe

July 20th, 2008 at 4:43 pm

Posted in Ruby on Rails

Tagged with , , ,

Formatting dates for SQL queries in Rails

without comments

Here’s a simple and clean way to format date for use in SQL query in Ruby On Rails.

User.find :all, :conditions => ['created_at > ?', 7.days.ago.to_formatted_s(:db)]

You can use to_formatted_s(format) method with different data types - Date, Time, DateTime, Range, Array and BigDecimal. There are also more formats available apart from :db. Find out more in Rails API.

Written by Michał Szajbe

July 1st, 2008 at 5:40 pm