Any way to create a hidden field in forms for resources with belongs_to association

I learn Rails by writing simple TODO assignments. Two models:

class List < ActiveRecord::Base has_many :tasks, :dependent => :destroy # ... end class Task < ActiveRecord::Base belongs_to :list # ... end 

Tasks are routed as embedded resources in the list. Therefore, when a new task is created by the user, a POST message is sent to /lists/:list_id/tasks . While in the view form Tasks#new there is

 f.hidden_field :list_id, :value => params[:list_id] 

but this is a terrible decision, because anyone can change the meaning of this hidden field.

What is the agreement here? Should I put something like

 @task.list_id = params[:list_id] 

in Tasks#create action and get rid of the hidden field, or maybe

 @task = List.find(params[:list_id]).tasks.new(params[:task]) if @task.save # ... end 

or is there a better way that I don't know about?

Edit:
Yes, there was a similar question well , and his answer pretty much touched my question. If you have another, send it.

+6
ruby-on-rails
source share
2 answers

You are right - that would be terrible. No need for hidden fields. Something like the following.

In TasksController :

 def new @list = List.find(params[:list_id]) @task = @list.tasks.build end def create @list = List.find(params[:list_id]) @task = @list.tasks.new(params[:task]) # etc end 

In the Task#new view:

 <% form_for [@list, @task] ... %> ... <% end %> 
+9
source share

If you are concerned about security (for example, one user creating to-dos in other user lists), and I assume that you because you did not want to use a hidden field that states that anyone can change value of that hidden field ) , I donโ€™t look how the @ bjg solution is better than yours, since you still get @list from params , and anyone can manipulate the parameters in the browser (changing the URL for publishing is as simple as changing the value of the hidden field) .

One common way to solve this problem without having to implement a more complex resolution is to simply use the current_user association, for example:

 def new @list = current_user.lists.where(id: params[:list_id]).take @task = @list.tasks.build end def create @list = current_user.lists.where(id: params[:list_id]).take @task = @list.tasks.new(params[:task]) # etc end 

That way, no matter what the params [: list_id] value is (it could have been manipulated by the user), you can be sure that @task will end up in this user account since @list will only find the entry related to current_user .

You can create this in a real application by returning an error message if @list is not found.

0
source share

All Articles