Link_to parameters ignored

Hi,

I've faced a couple of times the next problem.

I have a link to like:

<%= link_to 'Add comment', :action => 'add_comment', :program_id =>
program.program_name, :user => @username %>

I have function in the right controller:

def add_comment
  @program_id = params[:program_id]
  @user = User.find(session[:uid])
end

And that fails with:
Couldn't find Program with ID=add_comment

When I check the request sent to the server:

Processing ProgramsController#show (for 127.0.0.1 at 2008-02-27
13:37:19) [GET]
  Session ID: BAh7.....
  Parameters: {"user"=>"user1",
               "program_id"=>"The program",
               "action"=>"show",
               "id"=>"add_comment",
               "controller"=>"programs"}

←[4;36;1mProgram Columns (0.010000)←[0m ←[0;1mSHOW FIELDS FROM
`programs`←[0m
←[4;35;1mProgram Load (0.010000)←[0m ←[0mSELECT * FROM `programs`
WHERE (`programs`.`id` = 0) ←[0m

i guess you have added a RESTful route for this?

map.resource :programs

your link generates:
/programs/add_comment?program_id=.... (and it's a GET request as with
ever normal link)

and the RESTful url for the show action of this controller is:
/programs/:id
when it's a GET request, this routes to the show action. So the
resource sees "add_comment" as :id

In a RESTful design, adding comments should be handled in the
CommentsController, not the ProgramsController anyways.

Thorsten wrote:

i guess you have added a RESTful route for this?

map.resource :programs

Well no I haven't done anything like that. It is a basic rails app
generated with scaffold. Should I post here some configuration file to
help clarifying the issue?

To the main scaffold I have added a new add_comment.html.erb
I try to open that one from the index.html.erb

This is my controller. I have some basic authentication also in place
but that should be ok and is working.

class ProgramsController < ApplicationController

before_filter :check_auth, :except => :index

  def add_comment()
    @program_id = params[:program_id]
    @user = User.find(session[:uid])
  end

def secret
    puts session[:uid]
    @user = User.find(session[:uid])
    puts @user.username
    redirect_to :action => 'list'
  end

  def log_out
    session[:uid] = nil
    redirect_to :controller => 'main'
  end

  # GET /programs
  # GET /programs.xml
  def index
    @isLogged = false
    if session[:uid]
      @user = User.find(session[:uid])
      @isLogged = true
      @username = @user.username
    end

    @programs = Program.find(:all)
    @multiplier = -25

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @programs }
    end
  end

  # GET /programs/1
  # GET /programs/1.xml
  def show
    @program = Program.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml { render :xml => @program }
    end
  end

  # GET /programs/new
  # GET /programs/new.xml
  def new
    @program = Program.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml { render :xml => @program }
    end
  end

  # GET /programs/1/edit
  def edit
    @program = Program.find(params[:id])
  end

  # POST /programs
  # POST /programs.xml
  def create
    @program = Program.new(params[:program])

    respond_to do |format|
      if @program.save
        flash[:notice] = 'Program was successfully created.'
        format.html { redirect_to(@program) }
        format.xml { render :xml => @program, :status => :created,
:location => @program }
      else
        format.html { render :action => "new" }
        format.xml { render :xml => @program.errors, :status =>
:unprocessable_entity }
      end
    end
  end

  # PUT /programs/1
  # PUT /programs/1.xml
  def update
    @program = Program.find(params[:id])

    respond_to do |format|
      if @program.update_attributes(params[:program])
        flash[:notice] = 'Program was successfully updated.'
        format.html { redirect_to(@program) }
        format.xml { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml { render :xml => @program.errors, :status =>
:unprocessable_entity }
      end
    end
  end

  # DELETE /programs/1
  # DELETE /programs/1.xml
  def destroy
    @program = Program.find(params[:id])
    @program.destroy

    respond_to do |format|
      format.html { redirect_to(programs_url) }
      format.xml { head :ok }
    end
  end

  private
  def check_auth
    unless session[:uid]
      flash[:error] = 'You need to be logged in to access this panel'
      redirect_to :controller => 'main'
      #redirect_to :action => 'list'
    end
  end

end

Thanks.

in Rails 2.0 scaffold generates a RESTful controller and also adds the
RESTful route to the routes.rb
Have a look at the routes file and you will see it.

You can see what i described in my above reply in your own controller
code genrated bx the scaffold:

# GET /programs/1
# GET /programs/1.xml
  def show

a link like /programs/1 is routed to the show action.
same for /programs/add_comments, as Rails doesn't restrict URLs to
integer id values (we all love permalinks don't we?)
thats why your error happens.

While I believe Thorsten is correct about the part that the scaffold
is playing in the error, you'll need a couple more pieces to pull this
together.

First, the RESTful ProgramsController is going to assume that you're
dealing with the Program model, so it expects :id rather
than :program_id. That will help with creating the correct route.

Second, to support 'add_comment' as a non-standard (ie., not a default
Rails RESTful route) path you'll have to modify your /config/
routes.rb The scaffold should have added a line like the one Thorsten
mentioned. You'll want to change it to something like this:

map.resources :programs, :member=>{:add_comment=>:post}

That tells the routing system that you want to find one member in the
collection of Program routes (so expect an :id entry in the params
hash), that the action/method handling it will be called add_comment,
and it should only respond when accessed via http POST.

HTH,
AndyV

comopasta Gr wrote:

Hi,

I've faced a couple of times the next problem.

I have a link to like:

<%= link_to 'Add comment', :action => 'add_comment', :program_id =>
program.program_name, :user => @username %>

Processing ProgramsController#show (for 127.0.0.1 at 2008-02-27
13:37:19) [GET]
  Session ID: BAh7.....
  Parameters: {"user"=>"user1",
               "program_id"=>"The program",
               "action"=>"show",
               "id"=>"add_comment",
               "controller"=>"programs"}

Plus the action received at the server is now "show". When I have
specified "add_comment".

What is going on, any hints?

Thanks.

You might try adding the '{' and '}' around the action. Looking on the
documentation all the examples have those braces. I have had link_to and
link_to_remote do strange things when I leave those off. Good luck,

-Shandy

Hi again!

Thanks all for your great comments.
I actually tried to play intially with the {...} and so but didn't help.

REST was one of my pending (one of many) areas and it looks like time
has come. I just went through a perfect set of articles about the REST
for me. I think I might have a basic knowledge of the main concepts.

Here's a link to the set of articles, started with Rails 1.2 and updated
to 2.0: http://www.softiesonrails.com/search?q=rest+101

Best to modify the CommentsController.