Rails 4 - Rendering partial with access to class - ruby-on-rails

I have two classes Bid (has_many :mozs) and Moz (belongs_to :bid). I am trying to render a partial for creating Moz objects.
<%= f.fields_for :mozs do |builder| %>
<%= render "moz_fields", :f => builder %>
<% end %>
in my partial:
<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= f.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
When the contents of the partial are in the fields_for tag:
<%= f.fields_for :mozs do |builder| %>
<div class="field fields">
<%= builder.label :url, "Comparative URL" %><br>
<%= builder.text_field :url %>
<%= builder.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>
then everything works fine. But I need it in a partial to dynamically add the fields. When I keep it in a partial I get this error: undefined method `url' for NilClass:Class.
I don't understand why the class would be nil just because I put it in a partial.

I think the problem will likely be with your rendering of a partial inside the fields_for tag && you're not using the locals argument:
<%= render partial: "moz_fields", locals: { f: builder } %>
#moz_fields
<%= f.fields_for :mozs do |b| %>
<div class="field fields">
<%= b.label :url, "Comparative URL" %><br>
<%= b.text_field :url %>
<%= b.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>

Related

Rails: split a nested form into partials

I have a nested form which works perfectly fine, however, I'm trying to figure out how to split that nested form into a partial.
original form:
<%= form_for(#user) do |f| %>
<%= f.fields_for :achievements, Achievement.new do |ff| %>
<div class="field">
<%= ff.label :certification_name, 'Cert Name' %>
<%= ff.text_field :certification_name %>
</div>
<% end %><!-- fields_for -->
<%= f.submit 'Save', id: "submit-achievement", class: 'btn btn-primary' %>
Here's what I'm trying to do....
<%= form_for(#user) do |f| %>
<%= f.fields_for :achievements, Achievement.new do |ff| %>
<%= render partial: 'achievements/new_certification' %>
<% end %><!-- fields_for -->
<%= f.submit 'Save', id: "submit-achievement", class: 'btn btn-primary' %>
here's the partial.
<div class="field">
<%= ff.label :certification_name, 'Cert Name' %>
<%= ff.text_field :certification_name %>
</div>
the problem is that it doesn't know what to do with the 'ff' variable.
ActionView::Template::Error (undefined local variable or method `ff' for #<#<Class:0x007fdccd5498c0>:0x007fdcc04894d8>):
You can achieve this by passing a local variable to your partial like so:
<%= render partial: 'achievements/new_certification', locals: {ff: ff} %> # not a fan of the naming
Then in achievements/_new_certification.html.erb
<div class="field">
<%= ff.label :certification_name, 'Cert Name' %>
<%= ff.text_field :certification_name %>
</div>
Documentation on partials

Extend forms without page reload, rails

I'm searching for a solution to extend my form without page reload.
First I tried to render a partial with coffee or javascript, but escape_javascript didnt work.
Here's the view
<%= form_for #recipe = current_user.recipes.build do |f| %>
<%= f.label :name, "Recipe Name" %>
<%= f.text_field :name %>
<%= button_to "Add Ingredient", '#', class: "btn btn-lg btn-primary", id: "add" %>
<p></p>
<%= f.submit class: "btn" %>
<% end %>
The form above should be extented with following partial by every click on the button
<div id="recipe-ingredients">Quantity
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= render 'quantity_fields', f: quantity %>
<% end %>
</div>
_quantity_fields
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
This approach did not work (recipes.js.erb)
$(document).ready(function() {
$("#add").click(function() {
$("p").append("<%= escape_javascript
render(:partial => 'quantities') %>");
});
});
There's a workaround (see below) but I'm searching for a better solution.
$(document).ready(function() {
$("#workout-week").append(<%= escape_javascript(
Haml::Engine.new(File.read(File.join(Rails.root,'app/views',
'_show_period.html.haml'))).render(Object.new, period: #period)) %>);
});
A second approach is to write following lines in Coffee or JavaScript:
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
<% end %>
I'm a newbie so take this with a grain of salt, but have you tried using render :foo instead of redirect_to :foo in the appropriate controller function?
I solved it with cocoon
<%= form_for #recipe do |f| %>
<div class="field">
<%= f.label :name %>
<br/>
<%= f.text_field :name %>
<%= f.fields_for :quantities do |quantity| %>
<%= render 'quantity_fields', :f => quantity %>
<% end %>
<div class="links">
<%= link_to_add_association 'add', f, :quantities %>
</div>
</div>
<%= f.submit %>
<% end %>

Rails 4 - Nested Object Won't Save

Note: I've read a couple posts similar to this. But non of the solutions answer my question
I have two objects, Bid and Moz. When I build my Bid object, everything seems to save okay, except for the Moz objects.
Model
class Bid < ActiveRecord::Base
belongs_to :user
has_many :mozs, :dependent => :destroy
accepts_nested_attributes_for :mozs, :allow_destroy => true
end
class Moz < ActiveRecord::Base
belongs_to :bid
end
Bids::Build Controllers
class Bids::BuildController < ApplicationController
include Wicked::Wizard
steps :intro, :problems, :solutions, :pricing
def show
#bid = Bid.find(params[:bid_id])
render_wizard
end
def update
#bid = Bid.find(params[:bid_id])
#bid.attributes = build_params
4.times { #bid.mozs.build } if step == steps.second
render_wizard #bid
end
def new
#bid = Bid.new
redirect_to wizard_path(steps.first, :bid_id => #bid.id)
end
def build_params
params.require(:bid).permit(:client_name, :intro, :prob1, :prob2, :prob3, :site_feel, :search_phrase, :page_score, :total_links,
:internal_links, :external_links, :competition, :complete, :user_id, :us_company, :philosophy_1,
:philosophy_2, :website_conclusions, :is_onsite_seo, :onsite_seo, :is_ongoing_seo, :ongoing_seo,
:is_ppc, :ppc, :is_social_media, :social_media, :is_google_places, :google_places, :is_adwords_express,
:adwords_express, moz_attributes: [:url, :id, :_destroy]
)
end
private
def finish_wizard_path
root_url
end
end
solutions.html.erb
<%= form_for (#bid), url: wizard_path do |f| %>
<% if #bid.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#bid.errors.count, "error") %> prohibited this bid from being saved:</h2>
<ul>
<% #bid.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% if #bid.is_onsite_seo? %>
<div class="field">
<%= f.label :onsite_seo %><br>
<%= f.text_area :onsite_seo %>
</div>
<% end %>
<% if #bid.is_ongoing_seo? %>
<div class="field">
<%= f.label :ongoing_seo %><br>
<%= f.text_area :onsite_seo %>
</div>
<% end %>
<div class="field">
<%= f.label :ppc %><br>
<%= f.text_area :ppc %>
</div>
<div class="field">
<%= f.label :social_media %><br>
<%= f.text_area :social_media %>
</div>
<div class="field">
<%= f.label :google_places %><br>
<%= f.text_area :google_places %>
</div>
<div class="field">
<%= f.label :adwords_express %><br>
<%= f.text_area :adwords_express %>
</div>
<%= f.fields_for :mozs do |builder| %>
<%= render partial: "moz_fields", locals: {f: builder} %>
<% end %>
<%= link_to_add_association "Add URL", f, :mozs %>
<div class="actions">
<%= f.submit %>
or <%= link_to "skip this step", next_wizard_path %>
</div>
<% end %>
_moz_fields.html.erb
<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= f.hidden_field :destroy %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
I don't understand why they won't save. In addition, I noticed something odd -- when I don't use a partial for the nested object and use the f form builder for the #bid object (as opposed to 'builder'), I get an error no method or variable :url, but a Moz object is saved (although, not with any of the desired attributes).
My opinion that you misspelled with permit attrbibutes hash, try to change moz_attributes to mozs_attributes.
params.require(:bid).permit(..., :mozs_attributes: [:url, :id, :_destroy])
If you send the parameter _destroy: 1 through your hidden field
<%= f.hidden_field :destroy %>
you instruct Rails to destroy the child moz object, or in your case, prevent it from being created.
As for the second part of your question, if you inline the partial from this
<%= f.fields_for :mozs do |builder| %>
<%= render partial: "moz_fields", locals: {f: builder} %>
<% end %>
to this
<%= f.fields_for :mozs do |builder| %>
<div class="field fields">
<%= f.label :url, "Comparative URL" %><br>
<%= f.text_field :url %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>
it won't work, because the model object for the scope f is your #bid, not moz. Bids have no url attribute, hence the error.
With the input fields being created in the wrong form builder scope, you did not actually transmit any attributes for your moz object, and so it was created blank. As a side effect, this also meant not sending the _destroy parameter, so the object was saved.
Instead, inline the partial like this (I renamed builder to moz for clarity):
<%= f.fields_for :mozs do |moz| %>
<div class="field fields">
<%= moz.label :url, "Comparative URL" %><br>
<%= moz.text_field :url %>
<%= link_to_function "remove", "remove_fields(this)"%>
</div>
<% end %>

How to ensure all nested attributes show during 'edit'

I currently have a nested model User has_many Sales_Orders has_many Items.
I can create the Sales_Order with nested Items properly but when I try to 'edit' the Sales_Order, the Sales_Order information is visible but the Items are not shown. Any idea why these wouldn't show?
[sales_orders_controller.rb]
...
def edit
#sales_order = SalesOrder.find(params[:id])
end
[edit.html.erb]
<% provide(:title, "Edit SO") %>
<h1>Edit Sales Order</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#sales_order) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="span3">
<%= f.label :so, "SO#:" %>
<%= f.text_field :so %>
<%= f.label :customer, "Customer:" %>
<%= f.text_field :customer %>
<%= f.label :enter_date, "Date Entered:" %>
<%= f.text_field :enter_date, value: date_formatter(#sales_order.enter_date) %>
<%= f.label :request_date, "Request Date:"%>
<%= f.text_field :request_date, value: date_formatter(#sales_order.request_date) %>
<%= f.label :comments, "CS Comments:" %>
<%= f.text_area :comments %>
</div>
<div class="span3">
<% f.fields_for #sales_order.items do |builder| %>
<%= render 'item_fields', f: builder %>
<% end %>
</div>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
[_item_fields.erb]
<fieldset>
<%= f.label :item_code, "Item Code:" %>
<%= f.text_field :item_code %>
<%= f.label :qty_in_kg, "Qty (kg):" %>
<%= f.text_field :qty_in_kg %>
<%= f.label :qc_comments, "Comments:" %>
<%= f.text_field :qc_comments %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
<% f.fields_for #sales_order.items do |builder| %>
should be
<%= f.fields_for #sales_order.items do |builder| %>
Without the = you're building the output in the loop but never rendering/printing the return value (the generated HTML output).
Use <%= f.fields_for #sales_order.items do |builder| %>
Notice the = sign. This implies, "evaluate and embed"

Rails 3.2 nested_form gem: how to create link_to edit_model_path() in fields_for partial

I have a nested form, that uses the partial method for rendering the fields for the nested modal
<%= nested_form_for [:admin, #proforma] do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :elements %>
<p><%= f.link_to_add "Add element to proforma", :elements %></p>
<p><%= f.submit %></p>
<% end %>
In my partial I want a link to take you to edit the nested model instance e.g.
<div class='element-children'>
<p>
<%= collection_select(:element, :component_id, Component.all, :id, :name) %>
<%= f.text_field :name %>
<%= f.text_field :detail %>
<%= link_to 'Edit', [:admin, edit_element_path(#element)] %> |
<%= f.link_to_remove "Destroy" %>
</p>
</div>
However #element is not available in the partial. How can I reference the correct element?
Edit...
Solution using comment from Bradley
<div class='element-children'>
<p>
<%= collection_select(:element, :component_id, Component.all, :id, :name) %>
<%= f.text_field :name %>
<%= f.text_field :detail %>
<%= link_to 'Edit', edit_admin_element_path(f.object.id) %> |
<%= f.link_to_remove "Destroy" %>
</p>
</div>

Resources