Hi,
Same question is in Link_to parameters ignored - Rails - Ruby-Forum but since
it evolved from a different question I move it to its own topic.
I have some resources: Programs, Users and Comments.
Users make comments about programs.
I want to create a RESTful web service.
So I have generated 3 scaffolds and I can CRUD each of them separately.
In the models I have defined the belongs_to and has_many accordingly
From the Programs list I want to add a link next to each program in the
list so I can view what comments we have for that precise program.
I know I can use <%= link_to ‘View comments’,
:controller => ‘comments’, :action => ‘index’ %> and that will get me to
the general list of comments for all the programs.
But I want to see only the comments for a given program. So I guess I
can
add the program.program_name somehow in the link_to.
But do I need to add a new method to the comments controller? Or should
I modify the comments controller index/show method so that it would take
an argument and find the records accordingly? Would routes.rb take care
of that with some changes? What is the proper approach?
Thanks!
Hi again,
This is what I’ve done in the Programs index view:
<%= link_to ‘View comments’, :controller => ‘comments’, :action =>
‘index’, :program_name => program.program_name %>
And this in the comments controller index function:
GET /comments
GET /comments.xml
def index
if params[:program_name]
@comments = Comment.find(:all, :conditions => [“program_name = ?”,
params[:program_name]])
else
@comments = Comment.find(params[:id])
end
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @comments }
end
end
So do you thing that’s the right way?
Cheers
Hi,
My understanding of the RESTful way would lead me to using nested
resources in this situation
so your urls would be
/Programs/1/comments for index of all comments
for a program whose id is 1
/Programs/1/comments/new for new comments for a program
whose id is 1
/Programs/1/comments/10/show for showing comment 10 for a
program whose id is 1
and so on for all 7 crud actions. that way your comments controller
does not need logic like that.
so in your routes.rb you would do this
map.resources :programs do |program|
article.resources :comments
end
which will build all those routes for you you can check the routes
it creates by using
rake routes
from command line. it will list all of the routes that your
routes.rb file sets up. very useful for finding the correct
dynamic_url
for instance a few from my routes rb are
company GET /
companies/:id
{:action=>“show”, :controller=>“companies”}
company_profile GET /companies/:company_id/
profile/:id {:action=>“show”, :controller=>“profile”}
new_company GET /companies/
new
{:action=>“new”, :controller=>“companies”}
left hand column can be used by appending _url or _path accordingly
new_company_path in your index view for companies check your
scaffolded views and controllers and you’ll see them everywhere. the
table in rake routes shows the mappings
hope this helps 
Nathan
I’ve been now playing with this again.
Sorry to be back with the same one.
Yeah the rake routes is great to see all options clearly.
However I’m facing a problem:
This is what I have now in the routes:
map.resources :comments
map.resources :programs do |program|
program.resources :comments
end
Everthing is more or less working. I have created some programs and then
using “/programs/:program_id/comments/new” I have created some comments
for programs.
But, according to routes using “program_comments GET
/programs/:program_id/comments” should list all the comments for that
program id.
However that always shows all the comments for all the programs. That is
getting into the controller via the ‘index’ method which is:
GET /comments
GET /comments.xml
def index
@comments = Comment.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @comments }
end
end
And that finds all the comments as the code is. So how can it find
comments only for a give program with no changes in that controller?
that way your comments controller does not need logic like that.
map.resources :programs do |program|
article.resources :comments
end
I have changed article with programs in the code above. Is my routing
still ok?
I must be doing something wrong again…
Thanks.
On 2/29/08, comopasta Gr [email protected] wrote:
However that always shows all the comments for all the programs. That is
getting into the controller via the ‘index’ method which is:
GET /comments
GET /comments.xml
def index
@comments = Comment.find(:all)
And that finds all the comments as the code is. So how can it find
comments only for a give program with no changes in that controller?
You need to change your controller so you scope the comments by the
program, such as:
before_filter :get_program
private
def get_program
@program = Program.find_by_id(params[:product_id]) || Program.new
end
public
def index
@comments = @program.comments
end
Note that the above will only work when called in a nested fashion,
such as /program/123/comments
If you try calling /comments, you’ll get an empty list
Mike
sorry i probably mislead you by showing that route in my last mail as
an example, i would get rid of the index action and show action
instead use the program view and controller to display the comments
in the context of the program, i can’t really envisage a situation
where you would want to show all your comments in an index view. but
i suppose you might want to have the index show a list of comments
for a given program.
basically you would find the program based on params[:program_id] and
use it to populate @comments like so.
program = Program.find(params[:program_id])
@comments = program.comments.find(:all)
given that other actions in the view will use program variable you
could use a before_filter to create @programs variable that can be
referenced by all the actions. so for instance your new action can
be done like this:-
def new
@program.comments.build
end
check out this tutorial, I confess i haven’t read it thoroughly but
just skimming it i think it will explain all you will want to know.
http://www.akitaonrails.com/2007/12/12/rolling-with-rails-2-0-the-
first-full-tutorial
cheers
nathan
sorry again just realised mike had replied already …
I don’t
think you would actually want the comments controller to respond to
just /comments so I would remove
map.resources :comments
from your routes.rb file.
cheers
just noticed that you have both a nested route and a non nested route
for comments.
so if you want both ‘/comments’ and ‘/programs/123/comments’ to work,
you’ll need something like the following:
comments_controller.rb
def index
@program = Program.find_by_id(params[:program_id]) if
params[:program_id]
@comments = @program ? @program.comments : Comment.find(:all)
end
Mike
Hi, reply to myself (and anyone interested of course…)
<% form_tag :action=>"destroy", :controller=>"session" do %>
<%= submit_tag 'Log out' %>
<% end %>
So my problem what that the controller was not found in admin. So the
fix is to use :controller=>"/session"
That will look in root controller and that’s where it is found.
Cheers!
Hi,
Rolling with Rails 2.0 - The First Full Tutorial - Part 1 | AkitaOnRails.com
That is a great tutorial. I’m using it as a base for my drafts.
As an addition I’m using restful_authentication plugin and everything
goes ok but one thing.
In all the public views I have login and logout buttons for the user:
<% form_tag :action=>"destroy", :controller=>"session" do %>
<%= submit_tag 'Log out' %>
<% end %>
And I can login and logout just fine.
My problem now is that if I try to use the same in the views that are
inside Admin I get the next error:
No route matches {:controller=>“admin/session”, :action=>“destroy”}
I have to admit that the routes thing still is very cryptic to me.
My current routes file is:
map.resources :users
map.resource :session, :controller => ‘session’
map.root :controller => ‘programs’
map.resources :programs, :has_many => :comments
map.namespace :admin do |admin|
admin.resources :programs
end
map.signup ‘/signup’, :controller => ‘users’, :action => ‘new’
map.login ‘/login’, :controller => ‘session’, :action => ‘new’
map.logout ‘/logout’, :controller => ‘session’, :action => ‘destroy’
I’ll keep fighting but any ideas are welcome.
Cheers.