Best way to pass foreign_key value to Rails controller

It has been almost a week since I started digging deeper in forms, associations, hashes, symbols ... But, it seems, I cannot solve the puzzle without your help.

I am working on a project to display the content of different galleries. The main idea is that the user sees the names of the galleries (the names are links) to be able to click on the selected. Then all images belonging to this gallery are displayed. At the bottom there should be a link "Add image to this gallery."

My models:

class Gallery < ActiveRecord::Base attr_accessible :name has_many :pictures end class Picture < ActiveRecord::Base attr_accessible :image belongs_to :gallery end 

I created an index in gallery_id for the "picture" table.

My big problem appears here how to pass gallery_id to the new controller action. As I said in Agile web development with Rails, this could be:
<% = link_to 'Add image here ...', new_picture_path (: gallery_id => @ gallery.id)%>

As it seems in this case, foreign_key: gallery_id is displayed in the URL bar of the browser. The second problem is that: gallery_id is available for the function "new" of the controller, but "disappears" for the function "create" (causing the error "Could not find gallery without identifier"). The problem disappeared when I add a hidden field in _form for images, in my case:

 <%= form_for(@picture) do |f| %> <div class="field"> <%= f.hidden_field :gallery_id , :value=>params[:gallery_id] %> <%= f.label :image %><br /> <%= f.file_field :image %> </div> <div class="actions"> <%= f.submit "Create" %> </div> <% end %> 

Here are my definitions in the image controller:

 def new @gallery=Gallery.find(params[:gallery_id]) @ picture=@gallery.pictures.build end def create @gallery = Gallery.find(params[:gallery_id]) @picture = @gallery.pictures.new(params[:picture]) if @picture.save redirect_to(@picture, :notice => 'Picture was successfully created.') else redirect_to(galleries ,:notice => 'Picture was NOT created.') end end 

Finally, the definition of link_to in show.html.erb for galleries:

 <% for picture in selpics(@gallery) %> <div id= "thumb" > <%= image_tag picture.image %> </div> <% end %> <%= link_to 'Add a picture here...',new_picture_path(:gallery_id=>@gallery.id) %> 

Here is the debug output before sending the image: ---! map: ActiveSupport :: HashWithIndifferentAccess gallery_id: "6" action: new controller: photos

and after sending the "create" button (with raised exception):

 {"utf8"=>"✓", "authenticity_token"=>"IGI4MfDgbavBShO7R2PXIiK8fGjkgHDPbI117tcfxmc=", "picture"=>{"image"=>"wilsonblx.png"}, "commit"=>"Create"} 

As you can see, there is nothing like “gallery_id” in the “pictures” hash.

Summing up your questions for you:

  • Is there a way to pass foreign_key without hidden_field?

  • Is there any way to hide the foreign key form displayed in the URL string?

  • Is there an alternative when passing arguments using 'link_to'?

Thanks.

+4
source share
2 answers

You might want to consider the Rails tutorial on nested resources:

http://guides.rubyonrails.org/routing.html#nested-resources

In a nutshell:

routes.rb

 resources :galleries do resources :pictures do end # Generates the routes: /galleries/:gallery_id/pictures 

pictures_controller.rb

 def new @gallery = Gallery.find(params[:gallery_id]) @picture = Picture.new end def create @gallery = Gallery.find(params[:gallery_id]) # gallery_id is passed in the URL @picture = @gallery.build(params[:picture]) if @picture.save # success else # fail end end 

pictures / new.html.erb

 <%= form_for [@gallery, @picture] do |f| %> <div class="field"> <%= f.hidden_field :gallery_id , :value=>params[:gallery_id] %> <%= f.label :image %><br /> <%= f.file_field :image %> </div> <div class="actions"> <%= f.submit "Create" %> </div> <% end %> 

Ok, so gallery_id is still passed through the url, but I don't see anything wrong with that. You should pass it somewhere, right? You actually have only 3 reasonable options: either pass the hidden field as a querystring parameter or remove it inside the URL (embedded resource). Of the last 3, IMHO is the purest method.

If you want to make things even easier for yourself, I highly recommend looking into the pearl of Jose Valim Inherited Resources, which will take care of a lot of this trouble for you:

https://github.com/josevalim/inherited_resources

+7
source

You do not need to use a numeric identifier in RESTful routes. Look at permalink_fu and use the: permalink field, not: id to link to each gallery resource.

 /galleries/louvre /galleries/moma/382 

and

 ... new_picture_path(:gallery_id => @gallery.permalink) 

The key point here is the use of a symbolic unique key, which is not an identifier, as well as a link constant.

You can pass the permalink in the form of: id and update the actions of your controller to expect this.

0
source

Source: https://habr.com/ru/post/1342456/


All Articles