passing in parent id to remote_form partial on item creation - ruby-on-rails

I am still kind of fuzzy on controllers in rails, especially so because a lot of things seem to happen magically behind the scenes, and that's not happening in this case.
So say I have a person model, which has many photos (using paperclip) and has many favorite quotes. The quotes can have the text, the attributed author, etc. In both of those models, they are set as belonging to my person model.
Within a new person form, I used some code elsewhere to create a new photo:
<% form.fields_for :screenshots, :html => { :multipart => true } do |screen_form| %>
<%= render :partial => 'screenshot', :locals => { :form => screen_form } %>
<% end %>
The partial for that is very simple, like this (minus some ajax javascript stuff I put in for nested models):
<%= form.label :photo, "Screenshot:" %>
<%= form.file_field :photo %>
This all works fine and magically the ID of the person is associated with a screenshot upon creation in person_id. I don't even have a controller for screenshots and it still works.
However, it's not working for my quotes.
<% remote_form_for :quote, :html => { :method => :put }, :url => {:controller => "quote", :action => "create", :person_id => #person.id} do |quote_form| %>
<%= render :partial => 'quote', :locals => { :form => quote_form } %>
<% end %>
The partial for this is also very simple.
<%= form.label :quote_text %>
<%= form.text_field :quote_text %>
.........
<%= form.submit 'Create' %>
I am not really sure if I can put person ID in there, but it didn't complain. However it didn't work, either. The quotes controller is very simple.
def create
#quote = Quote.create(params[:quote])
end
Currently it gets put in the DB but person_id is not populated so I can't pull up the quotes associated with a particular person. Sorry if this is a silly question, but I'm kind of learning Rails by tweaking tutorials and mashing them together so bear with me :) It's just kind of mysterious how the photo thing works with NO controllers or special stuff and this doesn't.

The first form is a person form mainly that has snapshots fields associated to it, so looking at your HTML you will find something like person[snapshots][photo], this form will be submitted to person controller.
Passing person id to second form the is key to make it work, however it's a bit weird that it's not working, the form will submit to quote controller. Did you make sure(watch the log) that the params hash has person_id attribute?

Related

Rails: Nested form with STI inheritance informing forms, how to make work with AJAX?

Okay, first and foremost, I am doing something very complicated. It's possible I've gone in a wrong direction.
What I currently have is a STI inheritance model, StateDescription. Subclasses of StateDescription describe a specific state I could care about, such as "LocationHasItem" or "ItemNearOtherItem" or what not.
I understand that I may eventually want to upgrade this to a multi-table inheritance model, as not all subclasses of StateDescription use all possible variables (though there is a high degree of overlap).
These StateDescriptions are owned by another class in a "has_many/belongs_to" relationship.
So, inside the form for this other class, I have:
<%= f.fields_for :conditions do |e| %>
<br>
<%= render :partial =>"/state_descriptions/form", :locals => {:e => e, :universe => #story_section.universe, :div_id => "condition"}%>
<Br>
<% end %>
The StateDescription itself checks for which type it should render, then renders the appropriate partial like so (only showing one subclass, for clarity's sake):
<div id="<%=div_id%><%=e.object.id%>">
<li>
<%= e.select(:type, StateDescription.subclasses.collect{|x| x.to_s}) %>
<br>
<%= e.label "Inverted?" %>
<%= e.check_box :invert %>
<Br>
<% if e.object.type.to_s == "StateDescription::ItNear" %>
<%= render :partial =>"/state_description/it_nears/form", :locals => {:e => e, :universe => universe, :div_id => div_id}%>
<% end %>
<% end %>
</li>
</div>
The subclass partial looks like:
<%=e.collection_select 'item_id', universe.items, :id, :title%>
<%= e.object.title_middle_fragment%>
<%=e.collection_select 'item2_id',universe.items, :id, :title%>
Thus the form starts out the same for all subclasses, and only differs as required.
This works PERFECTLY and I was very happy with it...until I decided I wanted to have ajax update the webpage with the correct form when the sublclass is chosen out of select input field.
Then I realized I couldn't pass the form helper reference ("e" in this case) to the partial from a controller.
IS there a best practice for this case, or I am just doing something so complicated I should do straight jQuery or something and leave rails out of it?
If I put the entire form (including the things each subclass has in common) in each subclasses form, that doesn't seem very dry. Not only that, I'm not sure that I would be able to then associate the StateDescription subclass back up to the parent class...
But, if I do it AJAX, I suppose I could not worry about nested forms and just have the parent be a hidden field or something, and have the StateDescriptions save on their own through AJAX?
Would this be the best solution (if it even works?) or is there some simple Rails way that I am missing?
Well, I still don't know if this is the easiest, or DRYist way to do it, but I ended up putting the whole form in the partial, and then just not bothering with nested forms. This worked just fine with the AJAX solution.
It makes me sad to repeat the form elements they have in common every time, but it's worth it for the AJAX functionality.
I'll try making a bit more DRY, it occurs to me I could try making the subclass partial not need a form, but it could still call a super class form partial to insert the elements each subclass has in common.
I had a similar problem with STI model, which is owned by another class in a "has_many/belongs_to" relationship. In order to build the form for this other class dynamically, I used cocoon gem, together with simple_form.
Cocoon adds methods that dynamically add/remove fields for each concrete class, that inherits from your base STI class.
For example (Publication is the owner class, Item is the base STI model, and Post, Video and Image inherit from it):
# _form.html.haml
= simple_form_for #publication, :html => { :multipart => true } do |f|
= f.simple_fields_for :items do |item|
= render 'item_fields', :f => item
= link_to_add_association 'Add a Post', f, :items, :wrap_object => Proc.new { |item| item = Item.new }
= link_to_add_association 'Add an Image', f, :items, :wrap_object => Proc.new { |item| item = Image.new }
= link_to_add_association 'Add a Video', f, :items, :wrap_object => Proc.new { |item| item = Video.new }
= f.button :submit, :disable_with => 'Please wait ...', :class => "btn btn-primary", :value => 'Save'
The :wrap_object proc passes the concrete class to item_fields which renders the correct partials, such as image_fields or video_fields or whatever.
I hope this helps.
I wrote a longer explanation for this problem at: http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

Rendering an Edit partial while selected a defaulted value

I have a partial in my rails app that loads the vote form (It's just a select with numbers ranging from 1-5). I'm now making another partial that loads up if the user has already voted it's suppose to be an EDIt partial where you get selected the value that you voted and if you wanted to you could change it. But for some reason is not working, here's the code for it.
#Finds the vote by passing the user and the article
<%= #vote = Vote.find_vote_by(current_user,#article) %>
#Renders the partial with the vote variable loaded up with the vote that was found
<%= render :partial => "votes/edit_vote", :locals => {:vote => #vote} %>
And this is the partial
<% form_for(vote, :url => {:controller => 'votes', :action => 'edit'}) do |f| %>
<%= error_messages_for :vote %>
<p><%= f.hidden_field :article_id %></p>
<p>
<%= f.label :value, "Value for the vote: "%>
<%= f.select :value, {"1" => "1","2" => "2","3" => "3","4" => "4", "5" => "5"}, :selected => vote.value %>
</p>
<p>
<%= f.submit "Cloud-it!" %>
</p>
<% end %>
But for some reason the vote variable is not containing anything not the article_id, nor the value method, any ideas?
EDIT1: Per request here's what's debug #vote is outputting (It it indeed a sane value)
attributes:
created_at: 2010-09-02 14:39:04
updated_at: 2010-09-02 14:39:04
id: 1
value: 4
article_id: 1
user_id: 1
attributes_cache: {}
EDIT2
I tried clearing the partial code, in order to output this:
<%= debug #vote%>
<%= #vote.value %>
If i debug #vote it comes out perfect, will all the attributes and such. But whenever i add the second line it, It's not working it tells me that there's no .value, i tried .id, .article and nothing is as if it didn't exist. Any ideas?
EDIT3
Here's the vote by
named_scope :find_vote_by, lambda {|user,article| {:conditions => {:user_id => user, :article_id => article}}}
The reason behind it, it's that named scopes actually return named scopes, and you can't access the attributes just like it were a Vote class. I fixed this by changing the way to retrieve the vote and just forgetting about using that named scope. I accomplished it by using:
<% #vote = current_user.votes.find_by_article_id(#article)%>
which is a Rails method and actually returns a vote class. Then i just passed it to the partial and the magic worked!
Thank you so much to thenduks, without his help i couldn't had done it.
So first thing to fix is this line:
<%= #vote = Vote.find_vote_by(current_user,#article) %>
Should be:
<% #vote = Vote.find_vote_by(current_user,#article) %>
The former is for outputting in ERB and the latter is for executing arbitrary ruby code.
Next, put a line below that like so:
<%= debug #vote %>
And make sure it's a sane value. If not, paste the definition of your Vote class method find_vote_by.
EDIT: In that case it's probably just because using :locals => {...} makes instance variables, so you want #vote in your partial with the form.

How to produce several forms for a nested form?

Intro
I have an object #organization that has_many :quick_facts
Basically, I want to produce a _form for each :quick_fact but with one save button, that saves all of the quick_facts.
My two problems:
First Problem:
My quick_facts are not prepopulated with their information. They only appear as blank for each quick_fact I have.
Second Problem
A save button appears on every single form
My sad sad attempt :
- for quick_fact in #organization.quick_facts
- fields_for :quick_facts do |f|
= f.error_messages :header_message => FORM_ERROR_HEADER_MESSAGE, :message => FORM_ERROR_MESSAGE
= f.label :quick_fact, 'QuickFact'
%br/
= f.select :quick_fact, QUICK_FACTS, {}
%br/
= f.submit 'save', :class => 'button'
You really just want one form here, since you want to submit everything at once.
Here is what I would recommend:
Use a partial to render the label and the text option for the quick fact (if you want it to be text). You want this partial to be rendered once per quick fact, so use the :collection option on the render method to specify the collections of quick facts. Each partial will get its own local copy of whatever quickfact you are on, and a variable called quickfact_counter will also be created.
In addition, you will want to use the :locals option to pass the form to the partial as a local variable, so that you can do f.label, f.text_area
So, in conclusion, your new form will be something like this:
<% form_for #organization do |form| %>
<%= render :partial => "partial_name", :collection => #organization.quick_facts, :locals => {:form => form} %>
<%=form.submit 'save', :class => 'button'%>
<% end %>
Then your partial will just have
<%= form.label :quick_fact, 'QuickFact' %>
<%= form.text_field :quick_fact %>
If you wanted to get even fancier you could use a layout to render the form and have it defer to the partial, but this should be enough to get you started. Being able to pass a collection to a partial is one of my favorite Rails features.

Forms blank when rendering a partial when using a collection of objects. Help!

Alright, I know my title is a little obscure but it best describes the problem I am having.
Essentially, I have a list of users, and want to be able to edit their information in-line using AJAX.
Since the users are showing up in rows, I am using a partial to render the data and the forms (which will be hidden initially by the ajax), however, when the rows are rendered currently only the last item has it's form's fields populated.
I suspect this has something to do with the fact that all the form fields have the same id's and it is confusing the DOM. But I don't know how to make sure the id's are unique.
Here is a small example:
In my view:
<%= render :partial => 'shared/user', :collection => #users %>
My partial (broke down to just the form) note that I am using the local variable "user"
<% form_for user, :html => {:multipart => true} do |f| -%>
<%= f.label :name, "Name*" %>
<%= f.text_field :title, :class => "input" %>
<%= f.label :Address, "Address" %>
<%= f.text_field :address, :class => "input" %>
<%= f.label :description, "Description*" %>
<%= f.text_area :description, :class => "input" %>
<% end -%>
When the html is rendered each form has a unique id (for the id of the user) but the elements themselves all have the same id, and only the last user form is actually getting populated with values.
Does anyone have any ideas?? :)
Thanks in advance!
Alright, after having some lunch and regaining some brain cells, (and with a little help from Google) I figured this one out.
When passing a collection to a partial like this:
<%= render :partial => 'shared/user', :collection => #users %>
Rails creates a counter variable that you can use to define an index for the form in the form of "variable_counter":
<% form_for user, :index => user_counter, :html => {:multipart => true} do |f| -%>
This adds the index number to the form id as well as all the field id's and solved my little problem. :)
I hope this helps out someone else with this issue. :)

Ruby on Rails Country/State Select Enigma

I am trying to implement something seemingly very simple, and I have been beating my head against it for days at this point.
My desired end result is a Country select drop-down, tied to a State select drop-down, in such a way that when a given country is selected, IF states are known THEN those states are displayed in a select drop down, and if NO states are known for that country, then a text field is displayed instead.
I feel like I am almost there. At this point the interface will actually generate that list of states based on the persons' country, except it is refusing to update the drop-down dynamically.
The portion of my view where country and state location is gathered looks like:
# _person_setup.html.erb
<td>
<%= f.label :country, 'Select your country' %>*<br />
<%= f.select :country, Carmen::country_names, {},
{:style => 'width: 200px',
:id => 'country_select',
:onchange => remote_function(
:url => {:action => 'update_states'},
:with => "'country='+value")} %>
</td><td>
<p>
<div id="states_div">
<%= render :partial => 'states',
:object => Carmen::states(
Carmen::country_code(
#person.country)),
:locals => {:form => f} %>
</div>
</p>
</td>
The partial being referenced in the DIV is as follows:
# _states.html.erb
<% unless states.nil? or states.empty? %>
<%= form.label :state, 'Select your state' %>*<br />
<%= form.select :state, states.collect{|s| [s[0], s[0]]} %>
<% else %>
<%= form.label :state, 'Please enter state or province' %>*<br />
<%= form.text_field :state %>
<% end %>
Finally, the controller code which is intended to update the list of states dynamically:
def update_states
puts "Attempting to update states..."
q = params[:country]
states = Carmen::states(Carmen::country_code(q))
puts "Country = #{q}, states = #{states.collect{|s| s[0]}.join(", ")}."
render :update do |page|
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
end
puts "OK"
end
Now, this code is being called at the proper time and generating the appropriate lists of states. For example, when the user clicks Australia, "Attempting to update states... Country = Australia, states = Australian Capital Territory, New South Wales, Northern Territory, Queensland, South Australia, Tasmania, Victoria, Western Australia" shows up in the server process. However it doesn't update the page, and won't print the "OK" at the end. In short the line which is failing is undoubtedly
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
Note that replacing this line with
page.replace_html 'states_div', "<b>is it working</b>"
properly replaces the div, but of course not with anything useful.
Can someone help me understand what is going on here?
It looks like you're assuming that the #person variable is still available from your original action. This could be set up by a filter for the current person but you don't show that in your question.
If you do need to lookup the #person again you'll have to pass the id through in your remote_function I think.
Ryan Bates has a Railscast that shows how to select a category for a product or create a new category by typing the name. It sounds like a similar scenario to what you have, so you might want to check it out: Create Model Through Text Field.
This took me a full day to figure out something that would at least "work". I am also using Carmen and also messing with the select tag in a form_for model form (actually, fields_for nested within forms_for...which adds additional complications).
I would think there is a better solution but this worked for me. The select needs to be referenced by the form but the options don't. Thus, first time through, I use the Carmen state_select method which populates the select tag correctly and all the nested options tags. The second time through, I just replace the options. Take a look:
In the view, I chose to use an observe_field method since I do other things besides update the states (some other localization changes) but this should work for remote_function and others, too:
<%= address_form.country_select :country, {:prompt => "--Select One--"} %>
Don't be confused by the id (user_address_attributes_country) it is just my silly forms_for/fields_for implementation)
<%= observe_field :user_address_attributes_country, :url => { :action => :changecountry }, :with => 'new_country' %>
<%= address_form.state_select :state, #user.address.country, {:prompt => "--Select One--"}, :style => 'width: 90px' %>
Then in my controller, it just looks like this:
def changecountry
c = params[:new_country]
respond_to do |format|
format.html
format.js {
render :update do |page|
page['user_address_attributes_state'].innerHTML = \
"<option>--Select One--</option>" + state_options_for_select(nil, c)
end
}
end
end
Note: state_options_for_select is also from Carmen. I could not get it to work unless I put it inside the respond_to block where I guess the view helpers are available. Also, I hard code user_address_attributes_state which is my nested id generated from the form_for/fields_for address_form.state_select rendering call in the view.
I hope this helps. If anyone can do it better, believe me, I'm all ears. I'll change the design in time...but needed something that just worked today and this was the best I could figure out in a limited time.

Resources