0

This is a question which I am sure is easily solved and attributed in part to my own lack of knowledge, but I've done a bit of searching and can't figure out the proper solution to my problem.

In my situation, I have a class Product which has many Review objects. The reviews also belong to Users. Assuming I have defined my models correctly, I am having difficulty in figuring out how to correctly pass a :product_id variable into the review in order to tie a given review to a given product upon submission.

What I have thus far is a view displaying product information as well as a link_to in the form of <%= link_to 'Review Product', new_review_path(:product_id => @product.id) %>. The resulting view form for adding a new review (intended to be for that product) appears at least somewhat correct, as the URL displays as http://localhost:3000/reviews/new?product_id=1. I have done prior searching, as I mentioned, and similar answers to my sort of question have been provided, but it has not resolved the issue, as when I display the values of the @review instance variable, each property is nil.

In my reviews_controller.rb file, I can assign these variables -- at least within the new action's form, by doing something similar to the following:

@review = Review.new(:product_id => params[:product_id])

I can also assign the user_id variable by doing something similar and passing the current_user variable (handled by the devise gem). I am aware that the create action which Rails employs typically creates a new instance of the variable, based on everything I have read. However, doing that causes a loss of data with the exception of the variables I have input in the form. Technically speaking, I should be able to pass the current_user variable in the create action, but I cannot pass over (or do not know how to pass over) the product variable. For what it's worth, I'm not using nested routes of any sort right now, but I don't know if that is a direct solution.

If anyone has a better understanding of what I might be able to do to solve this problem, I would appreciate the help. I'm sure that, as I hinted at, it's an amateur mistake.

P.S. I apologize if the question wording is awkward, as I'm not sure of the best way to describe it.

Paul
  • 1,175
  • 8
  • 15
  • You can take a look at [this guide](http://guides.rubyonrails.org/routing.html#nested-resources) about nested attributes . It seems to me that you should use nested routes . – R Milushev Nov 30 '12 at 22:54
  • I'll look at it. I was actually doing so before but perhaps I didn't implement it in a way that would solve my issue. – Paul Nov 30 '12 at 23:00
  • I've been in your situation - [here is my case](http://stackoverflow.com/questions/5207038/the-better-way-to-pass-the-foreign-key-value-to-the-rails-controller) – R Milushev Nov 30 '12 at 23:01

2 Answers2

0

If you don't use nested routes like Qumara suggests (and I would agree) then you need to set add the following to app/views/reviews/new.html.erb so that it is available to your create action.

<%= r.hidden_field :product_id %>

Keep in mind of course that this means I could hack your form and set my review to whatever product I wanted if I knew the product id. So you might want to think about that...

Philip Hallstrom
  • 19,673
  • 2
  • 42
  • 46
0

Nested resource routes is probably the best way to go.
@PhilipHallstrom's way works in form elements, but if your looking for the Restful approach:

# Add nested resource route 
# /config/routes.rb
resources :products do
    resources :reviews
end


# In your 'products/show.erb.html'; @product will be the instance you want to review
<%= link_to 'Review Product', new_product_review_path(@product) %> # gets you to ReviewController#new

# In your ReviewsController#new
@product = Product.find(params[:product_id])
@review = @product.reviews.new #this should have product_id


# In your 'reviews/new.erb.html'
<% form_for [ @product, @review ] %> # gets you to ReviewController#create


# In your ReviewsController#create
@product = Product.find(params[:product_id])
@review = @product.reviews.new(params[:review]) # params from the previous form
@review.user = current_user
@review.save

As far as passing current_user or @product through the form params that wont work. You can't technically pass an actual Ruby Object through HTTP.

current_user will still be there in the controller so there's no point, and its bad for security.

@product you will need to query the DB from the controller, using the product_id

strider
  • 5,674
  • 4
  • 24
  • 29