Posts Tagged with "rails"

Rails Tips

JUL

13

2008

1 comment

While there are no shortages of posts listing tips for Rails, or lesser-known Ruby methods, I decided to write this post because these are shortcuts or helpers that I didn't know about until fairly recently. I'm going to try and update this post as I discover new railties and rubyisms along the way, so check back every now and then.


Symbol#to_proc

This is really a Ruby method, but it makes running a collect or map on ActiveRecord objects much easier. Whereas before, you would do this:

@members = Member.find(:all).map { |member| member.name }

Now, you can simplify it to this:

@members = Member.find(:all).map(&:name)

Model Calculations

This will let you do simple calculations on any ActiveRecord model (as long as the field you're calculating is numeric).

Student.average(:grade) # finds the average grade for all students (returns a float)
Student.maximum(:grade) # finds the highest grade
Student.minimum(:grade) # finds the lowest grade
Student.sum(:grade) # the sum of all grades

Custom ActiveRecord Associations

Let's say you have a model called BlogPost and one called Comment. A blog post has many comments, but you also have a boolean field on comments called approved that signifies if it's been decided that the comment is not spam (like most comments are). This is what your BlogPost model might look like:

class BlogPost < ActiveRecord::Base
  has_many :comments
end

You can add custom associations for approved_comments and unapproved_comments to your model to make fetching these comments a lot easier.

class BlogPost < ActiveRecord::Base
  has_many :comments
  has_many :approved_comments, :class_name => 'Comment', :conditions => 'approved=1'
  has_many :unapproved_comments, :class_name => 'Comment', :conditions => 'approved=0'
end

All you have to do is specify the class name of the associated model and the conditions of the find. This makes it possible to easily access these associations from within your views.

You can now show the number of approved comments for each post.

<%= @blog_post.title %> - <%= @blog_post.approved_comments.count %> Comments

You can also easily list out the approved comments.

<%- @blog_post.approved_comments.each do |comment| -%>
  <%= comment.author %> said:
  <%= comment.content %>
<%- end -%>

UPDATE: Shawn reminded me this week about named_scope, which was added in Rails 2.1. It makes custom associations a bit easier and more full-featured. You can get the same approved and non-approved comments with named_scope:

class Comment < ActiveRecord::Base
  belongs_to :blog_post
  named_scope :approved, :conditions => ["approved = ?", true]
  named_scope :unapproved, :conditions => ["approved = ?", false]
end

Notice that now the named_scope declarations go in the Comment model instead of the BlogPost model like the custom associations. You get the approved comments for a post with this line:

<%= blog_post.comments.approved %>

You can also combine named_scope calls when selecting records. Suppose our Comment model now has a named_scope for both approved and unapproved comments, as well as comments made by anonymous authors.

class Comment < ActiveRecord::Base
  belongs_to :post
  named_scope :approved, :conditions => ["approved = ?", true]
  named_scope :unapproved, :conditions => ["approved = ?", false]
  named_scope :anonymous, :conditions => ["name = ?", 'Anonymous']
end

You can use this to find all of the approved comments for a post where the author is 'Anonymous'.

<%= blog_post.comments.approved.anonymous %>

To add even more functionality to named_scope, you can add conditions to the call on the fly.

<%= post.comments.approved.all(:conditions => ["created_at > ?", 2.weeks.ago]) %>

This will pass the additional date condition to the find, making it possible to refine your searches even more.


Render Partial with Collection/Object

This is how I've always done my partials.

The view (index.html.erb):

<%- @posts.each do |post| -%>
  <%= render :partial => 'post', :locals => {:post => post} %>
<%- end -%>

The partial (_post.html.erb):

<%= post.title %> written by <%= post.author %>

I can simplify the call to the partial down to only one line of code (the partial itself will stay the same).

<div id="all_posts">
  <%= render :partial => 'post', :collection => @posts %>
</div>

By specifying the collection option, the view will call the partial post for each item in the @posts array.

But, let's say I wanted to call the partial for only one post. The old way:

<div id="single_post">
  <%= render :partial => 'post', :locals => {:post => @post} %>
</div>

Not terrible, but we can make it easier with the object option.

<div id="single_post">
  <%= render :partial => 'post', :object => @post %>
</div>

This will call the partial, and pass it only the object that we specify. Shorter and cleaner.


RJS with link_to_function

If you have several things on your page that need to be updated, and you want to do it with a javascript call instead of an AJAX call to the server, you can do it by passing a block to the link_to_function method.

Suppose this is my view:

<div id="list">
  <p id="list_title"><%= @list.title %></p>
  <div id="list_items">
    <%= render :partial => 'item', :collection => @list.items %>
  </div>
  <%= link_to_function 'Change it up' do |page|
    page.replace_html 'list_items', 'New Item Title'
    page.hide 'list_items'
  end %>
</div>

This is a poor example, but hopefully you can see what I'm trying to illustrate here.


Simplified FIND in Rails 2.1

With the release of Rails 2.1, they've added some much-needed find methods for easily getting all, first and last records for a model.

@all_posts = Post.all
@first_post = Post.first
@last_post = Post.last

And, of course, you can pass conditions and order options to the new find methods.

@all_posts = Post.all(:order => :updated_at)
@first_post = Post.first(:conditions => ["title LIKE ?", '%Rails%'])
@last_post = Post.last(:order => 'created_at DESC')

Tagged: tutorial, tips, ruby, rails

Site Rewrite

JUN

08

2008

0 comments

I've been really lazy about updating the blog lately. I'd like to say that I've been busy working on some cool new project, but the reality is that I bought a PS3 a few months ago, and all of my free time has been taken up by Call of Duty 4 and Grand Theft Auto. By the way, if you're on PSN, send me a friend request (deadwards).

To try and force myself to get back into the blog, I decided to re-write it since Rails 2.1 was recently released. It was really funny looking at some of my old code (keep in mind, I originally wrote this blog as my first foray into Rails, circa May 06). All of the code has at least been refactored, and in many cases totally re-written. I've also added caching where I can to increase the speed a bit. Hopefully, this will be the kick in the ass I need to get back to blogging.

ps I finally broke down and created a Twitter account.

Tagged: rails, twitter

HTTP GET and POST requests with Ruby

NOV

07

2007

3 comments

A while ago, I was working on a project for a client that used a third-party newsletter generator for capturing and storing email addresses. To add an email address, the application spits out some code for a form that you can put on your site. A user supplies his name and email address, then submits the form and it gets stored within the third-party app's database.

The problem arose when they wanted to automatically subscribe not only people who requested subscriptions, but also everyone who used the online contact form AND anyone who used the 'email to a friend' feature on one of the interior pages. Obvious misgivings aside, I set out to do what I was told (like any good drone).

The problem was, I needed to do a POST request to subscribe the person to the third-party app, but I couldn't do that with a regular form because I was already posting to the actual action being invoked. Luckily, Ruby has a built in Net::HTTP class for generating GET and POST requests from within the code.

Here is the method I needed to add the POST request to:

def email_to_friend
  ...other code...
  # now, do the dirty work
  require 'net/http'
  # get the url that we need to post to
  url = URI.parse('http://www.url.com/subscribe')
  # build the params string
  post_args1 = { 'email' => params[:email] }
  # send the request
  resp, data = Net::HTTP.post_form(url, post_args1)
end

The post_form method returns a Net::HTTPResponse object and an entity body string (in Ruby 1.8, it only returns the Net::HTTPResponse object). You can also use the post method.

Similarly, you can perform a GET request on a URL like so:

require 'net/http'
result = Net::HTTP.get(URI.parse('http://www.site.com/about.html'))
# or
result = Net::HTTP.get(URI.parse('http://www.site.com'), '/about.html')

The get method returns a String.

That's simple enough, right?

Tagged: rails, get, post, tutorial

Adding multiple email attachments with Ruby on Rails

JUN

20

2007

9 comments

I was building some forms for a client that required the user be able to upload supporting documents along with the application. I had implemented emailable forms before with single attachments, but never multiple. Turns out, it was just as simple to do, I just needed to call the attach function for each file I wanted to attach.

Here is the method in my controller that calls the ActionMailer class to send the email, where params[:file1], params[:file2], and params[:file3] are the file_field_tag's from the form:

UPDATE: I've re-factored this after Shawn suggested that it could be simplified into an array and iterated over.

def submit_application
  @uploaded_files = []
  @uploaded_files << params[:file1]
  @uploaded_files << params[:file2]
  @uploaded_files << params[:file3]
  ContactMailer.deliver_email_with_attachments(params[:application], @uploaded_files)
  flash[:notice] = 'Your application has been submitted.  Thank you!'
  redirect_to application_home_url
rescue Exception => ex
  logger.warn(ex.message)
  flash[:notice] = 'Uh oh!  There was an error sending your application.'
  redirect_to :back
end

And here is the ActionMailer method that attaches the files. I just need to iterate over the files, calling attach for each one.

def email_with_attachments(application_fields={},files=[])
  @headers = {}
  @sent_on = Time.now
  @recipients = 'client@domain.com'
  @from = 'info@domain.com'

  @subject = 'Here are some file attachments'
  application_fields.keys.each {|k| @body[k] = application_fields[k]}

  # attach files
  files.each do |file|
    attachment "application/octet-stream" do |a|
      a.body = file.read
      a.filename = file.original_filename
    end unless file.blank?
  end
end

The "application/octet-stream" is the generic MIME type for attaching unknown file types.

Pretty simple!

Tagged: tutorial, rails, email attachment, actionmailer

Rails inline ERb effects on HTML structure

MAR

31

2007

1 comment

When using Ruby on Rails, ERb (embedded Ruby) is used a LOT in the X/HTML. There are two types of ERb,

An evaluation block:

<% some_code %>

And an output block:

<%= @print_this_variable %>

These blocks are necessary when using Rails, and I've noticed that when I do a 'View Source' (via the Web Developer addon for Firefox, of course), I see a lot of funky spacing and line breaking where the ERb's have been evaluated. Probably fine for most people, but it makes reading the outputted HTML code a hassle.

It turns out that there are really three ways to use the evaluation ERb that can affect your spacing and line-breaking.

Firstly, the output block is used just like you'd expect to use it. If your code says this:

<p>
  Text before ERb.
  <%= "code_goes_here" %>
  Text after ERb
</p>

The resulting HTML will look just like this:

<p>
  Text before ERb.
  code_goes_here
  Text after ERb
</p>

Evaluation block use #1: If you just put a block, it will cause a line break after the block in the HTML, so if you had this in your code:

<p>
  Text before ERb.
  <% some_code %>
  Text after ERb
</p>

The resulting HTML code would look like this:

<p>
  Text before ERb.

  Text after ERb
</p>

Evaluation block use #2: If you add a dash(-) at the end of the block, it will prevent it from adding a line break. So, if your code looks like this:

<p>
  Text before ERb.
  <% some_code -%>
  Text after ERb
</p>

The resulting HTML code would look like this:

<p>
  Text before ERb.
    Text after ERb
</p>

The line break is gone, but the space taken by the block is still there. That leads us to. . .

Evaluation block use #3: If you add a dash(-) at the beginning AND end of the block, it will prevent it from adding a line break AND remove the leading space it would have taken up. So, if your code looks like this:

<p>
  Text before ERb.
  <%- some_code -%>
  Text after ERb
</p>

The resulting HTML code would look like this:

<p>
  Text before ERb.
  Text after ERb
</p>

You'd never know there was a code block there! Is this useful? I don't know... maybe.

Tagged: erb, xhtml, rails


© 2010 Travis Roberts. All rights reserved.