0

I have several books that users can create and then create pages for them.

routes.rb:

resources :books do
  member do
    get 'pages'
  end
end

This gives a link to create a new page through /books/:book_id/pages

In that page I render a partial:

<%= render '/pages/new' %>

book controller:

def page
    @book = Book.find(params[:id])
    @page = @book.pages.new
end

But when params are passed to a page controller the book_id is lost:

pages controller:

def create
  @page = Page.new(params[:page])
   if @page.save          
     redirect_to @page
   else
     render 'new'
   end
end

Also error handling becomes difficult as after the redirect the id also disappears.

I believe rest of the application seems fine as when I create the page through console the book_id is preserved.

It is my first app so I'm not even sure if this is even the right way to approach it... How can I get this to work?

Thanks guys!

Jonas
  • 3
  • 1
  • 1
    I suggest you try `raise params.inspect` at first line of your controller's method. You'll see what is in params and where. – C404 Apr 03 '13 at 20:34

2 Answers2

0

One way to debug this is to use "puts" in your controller for params to see what actually exists. "puts" are like println's in java or echo's in PHP

Please post the contents of params when ran with this code

def create
  puts "params = #{params}"
  @page = Page.new(params[:page])
   if @page.save          
     redirect_to @page
   else
     render 'new'
   end
end
Catfish
  • 18,876
  • 54
  • 209
  • 353
  • The puts method did not work so I used raise params. It returned: {"utf8"=>"✓", "authenticity_token"=>"CLE1lhmvynv4CkzJuPwuRcBaG0t6IBIE2lym4US6oeE=", "page"=>{"heading"=>"A Heading", "text"=>"Projects everywhere!"}, "commit"=>"Create page", "action"=>"create", "controller"=>"pages"} – Jonas Apr 03 '13 at 20:55
0

Nested resources can be handled in such a way.

# config/routes.rb
resources :books do
  resources :pages
end

You can also restrict the actions being created by using only: [:index, :new] or except: [:destroy] on the resources call.

In your PagesController you would have the following params available.

GET /books/:book_id/pages/:id => creates a params[:book_id] and params[:id]

# app/controllers/pages_controller.rb
def create
  @book = Book.find(params[:book_id])

  @page = @book.pages.build(params[:page])

  if @page.save
    # ...
  else
    # ..
  end
end

Note that the method call for building a new object through the association is @book.pages.build instead of .new. You'll find out all about Rails associations and how to build and create the objects through association in the Rails Guides on ActiveRecord associations. Hope these pointers help.

If you want to debug incoming parameters, you can just raise them as C404 suggested above.

# in any controller
def any_method
  raise params.inspect
  # or in yaml format
  raise params.to_yaml
end
Thomas Klemm
  • 10,678
  • 1
  • 51
  • 54
  • Thank you! I considered using nested resources but I would be happy to access my pages using just /pages/:id instead of /books/:book_id/pages/:id. Do you think this is possible? – Jonas Apr 03 '13 at 21:02
  • Yes! You can have both routes at the same time, but should limit the new and create paths to the pages resources nested under books (as you will get the book_id nicely this way). [This answer](http://stackoverflow.com/questions/15420804/what-objects-should-be-passed-to-a-link-to-with-triple-nested-route/15421082#15421082) might help you on your way. Feel free to return here and ask any more questions when nescessary. – Thomas Klemm Apr 03 '13 at 21:07
  • Okay, had to play with the _path(@book, @page) a little, but all sorted. Now going to /page/:id drops the book id, but it is still in the db. Thanks! – Jonas Apr 03 '13 at 22:53