Rails: embedding and retrieving array from form - ruby-on-rails

I'm getting tripped up in Ruby, Rails & HTML syntax. Hoping some Rails ninja can help me with what's likely a trivial problem....
Post has_many Photos
Photo has a string :image attribute
In Post's _form.html.haml I would like to embed (in a hidden_field) the contents of the image attribute for each Photo associated with a Post...and then get it back out when form is submitted. I could do this either by A) adding one hidden_field for each photo.image or B) create a single array containing all associated photo.images.
I'm tripped up by how best to embed this...(A) or (B) neither of which I've fully perfected.
# _form.html.haml:
= form_for #post do |f|
- if #post.photos.any?
- #post.photos.each do |photo| -# (A)
= f.hidden_field :image_cache -# (A)
= f.hidden_field :images_cache -# (B)
= f.file_field :photos, :multiple => true
.actions
= f.submit 'Save'
#post.rb (A)
def image_cache
self.photos.any? ? photos.first.image : nil -# works with `first`
-# but not sure how to
-# pass id of others?!?
end
#post.rb: (B)
def images_cache
photos.map { |i| i.image }
end
Problem with (A) is I don't know how to pass the photo back to the Post model to return the image_cache attribute off of it?!? f.hidden_field :image_cache(photo) doesn't work
Problem with (B) is the images_cache returned by the Post model is an array but once embedded in the HTML page and returned by the following post request it has become a string representation of an array: [/uploads/tmp/20110729-1216-15902-2013/Before_Green_Flash.JPG, /uploads/tmp/20110729-1216-15902-5934/Before_Green_Flash2.JPG] and therefore does not respond to each.
Any help with either or both situations would be greatly appreciated!

For approach a, why not: = f.hidden_field photo.image

Related

Cocoon how to remove associations

I am trying to use the Cocoon gem to add/remove assets on asset_profiles. Everything up to this point works, I am just having a problem with link_to_remove_association. When the button is clicked, the field is removed. But if the field had been filled in and saved previously, I am unable to remove said association. The button just hides the field until I hit update. Is there a way to actually remove the association from the database through link_to_remove_association? Any help is much appreciated. Thanks in advance.
Here is the code I am referring to:
Asset.show
= simple_form_for([#asset_profile, #asset]) do |f|
= f.input :max_users, as: :hidden
#assets_users
= f.simple_fields_for :assets_users do |assets_user|
= render "assets_user_fields", f: assets_user
.links
= link_to_add_association "Add Another User", f, :assets_users
= f.submit
Asset._assets_users_fields
.nested-fields
= f.input :user_id, collection: #users.order(:last_name), :label => "User"
= link_to_remove_association "Remove", f
Screenshot of page pre-remove:
Screenshot of post-remove:
Screenshot of post-update(page reload):
I would much rather, after the update, the page be reloaded and looking like below, which is the form for initially adding users to an asset:
When using strong parameters, you have to make sure to permit :id and :_destroy, as documented by the way (see documentation ).
It is not unlogical: cocoon sets the _destroy if something needs to be removed, rails then needs the id to know what to remove.
Im my case, i forget for allow_destroy: true.
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Did you permit the nested parameter _destroy in either permit (strong_parameters) or attr_acceptible?
Your asset_profile_params should look like
def asset_profile_params
params.require(:asset_profile).permit(:max_users, :asset_users_attributes => {:user_id, :_destroy})
end

Form for taggable post model

I'm working in a form for post than can have tags. The relationship is a classic has_and_belongs_to_many between Post and Tag.
Problem is I can't initialize a post with an array of tag ids, like this:
Post.new(tags: [1, 2, 3, 4]) # won't wotk. ActiveRecord expects Tag instances
So my current form is like this:
= form_for #post do |f|
= f.text_field :title, placeholder: 'title...'
= f.text_area :body
= fields_for :'post[tags]' do |ft| # hacky. using #post.tags raised 'undefined `model name` for `#post.tags`'
- Post.tags.each do |tag| # I defined Post::tags since I can't Acces Tag class here
= ft.check_box tag.id
= tag.name
= f.submit 'Save'
This form forces me to hack a little in either the controller, but seems like a bad practice. I also thought I could override ActiveRecord::Base initializators to allow ids so my first example works, but surely I'm missing something here.
Try setting tags_singular_ids to your ids. You can check out http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many for more of the methods that has_and_belongs_to_many provides.
Easy and bit hacky solution:
# defined in my posts controller
def post_params
p = params.require(:post).merge(user: current_user)
p[:tags] = p[:tags].map do |id, value|
value == '1' ? Tag.find(id) : nil
end.compact!
p
end

Rails Parse Form Input

I'm using a form to transfer some data from one part of a controller to another (new to create), but I'm having some trouble with it. When I try to get the data after submitting the form, it just gives me a nil value.
Here's the form code:
<%= f.hidden_field :owner_id, :value => #tool.user_id %>
<%= f.hidden_field :tool_id, :value => #tool.id %>
<%= f.hidden_field :borrower_id, :value => current_user.id %>
And this is the create action in the controller:
def create
render text: params[:rental_agreement].inspect
#rental_agreement = RentalAgreement.create
#rental_agreement.owner_id = params[:owner_id]
# render text: #rental_agreement.inspect
end
When I hit the "Submit" button on the form, I see this:
{"owner_id"=>"3", "tool_id"=>"1", "borrower_id"=>"4"}
That's fine, but when I change which inspection renders (comment out the top line, uncomment the bottom), all it displays is:
#
And if I look in the Rails console at this object, all of the fields in it are nil (except the id and created_at fields).
I'm just trying to figure out how to assign the variables from the form (owner_id, tool_id, and borrower_id) to the rental_agreement variable. Any help is much appreciated!
Your create method seems wrong. Try this.
def create
#rental_agreement = RentalAgreement.new(params[:rental_agreement])
#rental_agreement.save
end

Generating unique HTML ids in Rails when using a repeated partial that has form_for

I have a view on my current project which does something like the following(in haml):
-#horses.each do |horse|
= render :partial => 'main/votingbox', :locals => {:horse => horse}
The in the _votingbox.html.haml file I have the following:
%div.votingbox
%span.name= horse.name
%div.genders
- if horse.male
%img{:src => 'images/male.png', :alt => 'Male'}
- if horse.female
%img{:src => 'images/female.png', :alt => 'Female'}
%div.voting_form
= form_for(Vote.new, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
...
a bunch of labels and input elements follow generated using the form helpers
This will generate working code but it does generate forms with the same ids for all the form elements which makes the HTML invalid once the votingbox partial is rendered a second time.
My first guess at fixing this was to specify a unique :id to form_for but that only applies to the form tag generated by form_for and not any of the tags inside the form_for block.
One definite solution to this problem is to go through and manually define my own unique ids on form_for and all the form elements I use. This is more work than I had hoped for.
Is there an easier or cleaner way to get unique ids in a similar format to the way Rails currently generates them on all my form elements?
I have removed the original answer as it is totally irrelevant to the updated version of the question.
Update: So now we know that you have an unsaved ActiveRecord object passed to the form_for call, the answer becomes simple: You can override any parameter that form_for generates. That includes the element id. And fields_for sets the context for a specific record.
= form_for(Vote.new, :url => horse_vote_path(horse), :id => dom_id(horse, 'vote')) do |f|
= f.fields_for horse, :index => horse do |fh|
= fh.text_field :whatever
…
You can override the autogenerated ids and names of all form_for content with :as like the following:
= form_for(Vote.new, :as => horse.name, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
So if a given horse.name is foobar, it will generate a comment field whose id is foobar_comment and name is foobar[comment]
But remember to make sure that the dynamic parameter is acceptable as an html id, a horse.name like hor$e is not acceptable as an html id and therefore might break something.
P.S: Sorry for answering very late, but at the time the question was asked, I haven't had learnt anything at all about rails! hope that might help someone out there!

Accessing objects in semantic_fieds_for loop / formtastic

Model has accepts_nested_attributes_for for the relation and the form is as follows:
= semantic_form_for #obj, :url => path do |f|
= f.inputs do
= f.input :name
= f.semantic_fields_for :photos do |p|
= p.inputs :desc
= f.buttons
The form works well and everything is fine. However, I would like to display each photo near the field, so the user could se which picture she is going to annotate. Is there anyway, to access photo.id inside the fields_for loop?
Edit:
Is there any way to alter the order in which photos fields will be rendered in this example. As far as I can tell till now, that order is pretty random.
Well this was easy enough, the object is accesible by:
p.object
:-)
Second part of the question is solved with:
default_scope order(...)

Resources