Reputation: 81
I'm looking to use :scope in my rails 3.1 app and need a little direction on how to implement them correctly. I understand that you write the logic in the model (to extract the data you need), but my question comes on the next steps.
For example: I have a "Piece" of information. Each "Piece" has a Topic and Audience among other things. I'd like to use scopes to display all "Pieces" of information for a given Topic or Audience without writing new actions in my controller.
Essentially, I'm not sure how to link to these views without creating new actions in the controller and then just using the typical link_to. I'd like to use the scopes I've written.
I'm looking for the correct (and most appropriate) way to get this done.
Thanks in advance for any help on this.
Upvotes: 1
Views: 2090
Reputation: 14205
You don't even need a scope for this. Check it out:
Piece.includes([:topic, :audience]).where(['`topics`.name = ?', 'Politics'])
With Rails 3 & Arel, most scopes are entirely unnecessary.
On using this in views without creating new controller actions, you can setup a some conditionals using params passed to your index action to determine how to accomodate the request.
app/controllers/pieces_controller.rb:
class PieceController < ApplicationController
def index
case params[:find_by]
when 'topic_name'
@pieces = Piece.includes([:topic, :audience]).where(['`topics`.name = ?', params[:topic_name])
when 'topic_id'
@pieces = Piece.includes([:topic, :audience]).where(['`topics`.id = ?', params[:topic_id])
else
@pieces = Piece.all
end
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @addressees }
end
end
# ...
end
app/views/pieces/index.html.erb:
<%= link_to 'Politics Pieces', :controller => 'pieces', :find_by => 'topic_name', :topic_name => 'Politics' %>
app/views/pieces/index.html.erb:
<%= select 'find_by', 'topic', find_by_topic_select_options %>
app/helpers/pieces_helper.rb: (moved link_to here for readibility)
module PieceHelper
def find_by_topic_select_options
Topic.all.collect do |topic|
url = url_for :controller => 'pieces', :find_by => 'topic_id', :topic_id => topic.id
[topic.name, url]
end
end
end
public/javascripts/application.js:
window.onload = (function (ev) {
var find_by_topic_select = document.getElementById('find_by_topic');
find_by_topic_select.onchange = (function (e) {
var selected = this.options[this.selectedIndex];
window.location = selected.value;
});
});
And, a footnote, you do not link_to
an association or a data structure. You link to a url or route which calls an action (which renders a view) which appropriately displays your data structure. I hope this clears things up for you.
Upvotes: 1
Reputation: 1393
Here is how I would do that:
In piece.rb
def self.scope_by_topic(topic_name)
topic_name.present? ? includes(:topic).where(topic: {name: topic_name}) : self.scoped
end
def self.scope_by_audience(audience_name)
topic_name.present? ? includes(:audience).where(audience: {name: audience_name}) : self.scoped
end
About the scoped
method I use hereover:
http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html#method-i-scoped
In you pieces_controller.rb
:
def index
@pieces = Piece.scope_by_topic(params[:topic_scope])
.scope_by_audience(params[:audience_scope]).all
# render view here
end
And in your view, you can use the following helper:
link_to "My piece of information", pieces_path(topic_scope: 'A topic', audience_scope: 'An audience')
The URL will look like:
http://www.example.com/pieces?topic_scope=A+topic&aucience_scope=An+audience
Upvotes: 0