Ok.. I'm new to Rails, and I know this has been asked before, but I'm still confused as to how to approach the following common problem. I can get the association to work, but having something magically work and starting rails with bad habits is not something I want to do.
Say I'm building a blog. I have two resources: Articles and Users. Each user has many articles, and each article belongs to one user:
rails g scaffold User name:string email:string
rails g scaffold Article user_id:integer title:string content:string
User Model:
class User < ActiveRecord::Base
has_many :articles
end
Article Model:
class Article < ActiveRecord::Base
belongs_to :user
end
Now, on my articles index, I can do something like:
…table headers...
<% @articles.each do |article| %>
<tr>
<td><%= article.user.name %></td>
<td><%= article.title %></td>
<td><%= article.desc %></td>
<td><%= article.content %></td>
<td><%= link_to 'Show', article %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
And all I need for that model association for the User Name is to put "@articles = Article.all" on the index action before the respond_to. Pretty cool!
What if I want to list all these articles (I'm skipping paging here for the sake of simplicity) on my Home page, using the index action on my Home controller?
I know I can do something like this in the Home Controller:
class HomeController < ApplicationController
def index
@articles = Article.joins(:user)
end
end
…and then I can access this data on my home->index view:
<div class="row">
<% @articles.each do |article| %>
<div>
<h3><%= link_to article.title,
:controller => "articles", :action => "show", :id => article.id %></h3>
<small>Posted on <%= article.created_at %> by
<a href="#"><%= article.user.name %></a></small>
</div>
<% end %>
</div>
First Question: When accessing the User data for all the Articles, should I be using a :joins or an :includes? It seems they both work, but I wonder which one is right in this situation, and which one generally performs faster.
@articles = Article.joins(:user)
-vs-
@articles = Article.includes(:user)
Second Question: In my scaffold for Article (building the migration), should I use user_id:integer or user:references. Do they do the same thing, or is one preferred over the other? If I use :integer as the field type, is it recommended that I also add an index for it (add_index :articles, :user_id)? I found a great RailsCast, and it does a great job of explaining, but I wonder if anyone else has another opinion.
If it helps, I'm on Rails 3.2.2.
Thanks!
You should be using @articles = Article.all :include => :user
to retrieve your records. Please read Rails :include vs. :joins for more information on why this is generally faster than :joins
. (Basically, it gives you the same information without duplicates.)
Rails has a shortcut for belongs_to
associations when it comes to migrations. Use belongs_to :user
and Rails will automatically include the user_id
column (of type integer
) for you.
Example:
class CreateArticle < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.belongs_to :user # Creates 'user_id' column
t.timestamps
end
end
end
First question:
You want to retrieve all the articles with their users data in an efficient way, you must use
@articles = Article.includes(:user)
You'll get the list of all articles in your DB, each article with its user already fetched.
With @articles = Article.joins(:user)
you'll get only the articles which have a User, and when you'll do article.user
on any of these articles, it would generate a new SQL request.
For more information: http://guides.rubyonrails.org/active_record_querying.html (if you have not already read this set of guides, I strongly recommend you to do it now).
Second question:
I use the user_id:integer
form. I'm not sure user:references
can be used in the rails g scaffold
command line. An index on the column 'articles.user_id' will improve the speed of retrieval when looking for articles of a specific user. Add this index only if your application will do this kind of search.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With