I have models like this
post.rb
has_many :items
accepts_nested_attributes_for :items
item.rb
has_one :heading, dependent: :destroy
has_one :content, dependent: :destroy
has_one :link, dependent: :destroy
has_one :movie, dependent: :destroy
has_one :photo, dependent: :destroy
has_one :quate, dependent: :destroy
accepts_nested_attributes_for :heading
accepts_nested_attributes_for :content
accepts_nested_attributes_for :link
accepts_nested_attributes_for :movie
accepts_nested_attributes_for :photo
accepts_nested_attributes_for :quate
heading,content,link,movie,photo,quate.rb
belongs_to :item
posts_controller.rb
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'created!!' }
else
format.html { render :new }
end
end
def post_params
params.require(:post).permit(:title, :description, :image,:user_id,
items_attributes:[:id, :order,
heading_attributes:[:id, :head],
photo_attributes:[:id, :image, :title, :q_url],
movie_attributes:[:id, :y_url],
quate_attributes:[:id, :quate, :q_url, :q_title, :q_comment],
content_attributes:[:id, :content],
link_attributes:[:id, :url, :l_text],
twitter_attributes:[:id, :t_url]
])
end
posts/new_and_edit.html.erb
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :description%>
<%= f.text_field :description %>
<%= f.label :image %>
<%= f.file_field :image %>
<%= f.hidden_field :user_id %>
<%= f.submit %>
<%= render 'posts/item_form_fields', name: 'headings' %>
<%= render 'posts/item_form_fields', name: 'contents' %>
<%= render 'posts/item_form_fields', name: 'movies' %>
<%= render 'posts/item_form_fields', name: 'quates' %>
<%= render 'posts/item_form_fields', name: 'links' %>
<%= render 'posts/item_form_fields', name: 'photos' %>
posts/_item_form_fields.html.erb
<%= form_for(#post, remote: false) do |m| %>
<%= render 'items/form_fields', m: m, name: name %>
<%= m.submit "submit" %>
<% end %>
items/_form_fields.html.erb
<%= m.fields_for :items, #item do |b| %>
<%= b.hidden_field :order, value: '0' %>
<%= render "#{name}/form_fields", b: b %>
<% end %>
headings/_form_fields.html.erb
<%= b.fields_for :heading, #item.build_heading do |h| %>
<%= h.text_field :head %>
<% end %>
"I have a "_form_fields.html.erb" for content,link,movie, photo and quate as well. "
when I run rails server, the nested-models form doesn't show up on view.
Also I pressed "submit", console said that
param is missing or the value is empty: post
I don't get why its happen.
Do you have any idea?
Thanks
You need to correct some important things
In your posts#new action
def new
#post = current_user.posts.build
#item = #post.items.build
#item.build_heading
#item.build_content
#item.build_link
#item.build_movie
#item.build_photo
#item.build_quate
end
And your form code after all the changes should look like this
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :description%>
<%= f.text_field :description %>
<%= f.label :image %>
<%= f.file_field :image %>
<%= f.hidden_field :user_id %>
<%= f.fields_for #item do |m| %>
<%= render 'items/form_fields', m: m %>
<%= render 'headings/form_fields', m: m %>
<%= render 'contents/form_fields', m: m %>
<%= render 'movies/form_fields', m: m %>
<%= render 'quates/form_fields', m: m %>
<%= render 'links/form_fields', m: m %>
<%= render 'potos/form_fields', m: m %>
<% end %>
<%= f.submit %>
<% end %>
And you need to change the contents of partials like below
#items/_form_fields.html.erb
<%= m.hidden_field :order, value: '0' %>
#headings/_form_fields.html.erb
<%= m.fields_for :heading do |h| %>
<%= h.text_field :head %>
<% end %>
And the same for the remaining partials as well.
Related
Alright, been looking everywhere for this one. Tried all the solutions. Maybe someone can help on this.
So, I have a WebRequest model that has many WebSites. Each WebSite belongs to a WebRequest. My problem is in the nested form. Ive gone in an permitted the params (atleast, based on the documentation I have) and everything works fine until I go into the server logs. Posted below
class WebRequest < ActiveRecord::Base
has_many :web_sites
accepts_nested_attributes_for :web_sites
end
and here is the WebSite model
class WebSite < ActiveRecord::Base
belongs_to :web_request, dependent: :destroy
end
_form.html.erb
<% 1.times do %>
<%= f.fields_for :web_site do |ff| %>
<%= ff.input :url %>
<%= ff.input :description %>
<% end %>
<% end %>
WebRequests Controller
class WebRequestsController < ApplicationController
def new
#web_request = WebRequest.new
# #web_request.web_sites.build
end
def index
#web_requests = WebRequest.all
end
def create
#web_request = WebRequest.new(web_request_params)
respond_to do |format|
if #web_request.save
RequestMailer.web_request_submit(#web_request).deliver
format.html { render partial: 'success' }
format.json { render action: 'show', status: :created, location: #web_request }
else
format.html { render action: 'new' }
format.json { render json: #web_request.errors, status: :unprocessable_entity }
end
end
end
def web_request_params
params.require(:web_request).permit(:web_needs, :primary_goal, :secondary_goal, : :call_to_action, :hero_image, :image_count, :existing, :resources, :web_examples, :special_functions, :social_network, web_sites_attributes: [:id, :url, :description])
end
end
And here is the server log:
Started POST "/web_requests" for 127.0.0.1 at 2014-07-10 15:56:12 -0400
Processing by WebRequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0iisNgGk/AhC4jRrp1cmKWVCBsCcSx5G2dueEI/+p2A=", "web_request"=>{"web_needs"=>"", "primary_goal"=>"", "secondary_goal"=>"", "call_to_action"=>"", "hero_image"=>"", "image_count"=>"", "existing"=>"", "web_site"=>{"url"=>"TROLL", "description"=>"TROLL"}, "resources"=>"", "special_functions"=>"", "social_network"=>""}, "commit"=>"Create Web request"}
Unpermitted parameters: web_site
Notice at how the form fields get passed but they get restricted out of making it to the DB.
THANKS!
Update::
Here is the full form path:
<%= simple_form_for(#web_request) do |f| %>
<% if #web_request.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#web_request.errors.count, "error") %>
prohibited this Web Request from being saved:</h2>
<ul>
<% #web_request.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="container">
<div class="field">
<%= f.input :web_needs, label: 'What web needs do you have?' %>
</div>
<div class="container"><h5>Please list below 5 URL's and explanations of why you like them.</h5></div>
<% 1.times do %>
<%= f.fields_for :web_sites do |ff| %>
<div class="field">
<%= ff.input :url, label: "URL of example site" %>
</div>
<div class="field">
<%= ff.input :description, label: "Description of example site" %>
</div>
<% end %>
<% end %>
<div class="field">
<%= f.input :resources, label: 'Will you be providing any kind of resource on this page? e.g. chord chart download.' %></br>
</div>
</div>
<div class="actions">
<%= f.button :submit, :class => "button" %>
</div>
</div>
<% end %>
Update::Full error log
undefined method `url' for #<ActiveRecord::Associations::CollectionProxy []>
The line is here
<% 1.times do %>
<%= f.simple_fields_for :web_site, #web_request.web_sites do |ff| %>
<div class="field">
<%= ff.input :url, label: "URL of example site" %> <--ERROR HERE on ':url'
</div>
<div class="field">
<%= ff.input :description, label: "Description of example site" %>
</div>
<% end %>
Add to controller in new action:
def new
#web_request = WebRequest.new
#web_site = #web_request.web_sites.build
end
and form:
<%= f.simple_fields_for #web_site do |ff| %>
<%= ff.input :url %>
<%= ff.input :description %>
<% end %>
<% end %>
and web_request_params:
def web_request_params
params.require(:web_request).permit(:web_needs,
:primary_goal,
:secondary_goal,
:call_to_action,
:hero_image,
:image_count,
:existing,
:resources,
:web_examples,
:special_functions,
:social_network,
{ web_sites: [:id, :url, :description] })
end
In your controller in web_request_params change web_sites_attributes for web_site_attributes
In your controller remove the comment from #web_request.web_sites.build
In your view remove 1.times do
In yor form change f.fields_for :web_sites do |ff| with f.simple_fields_for :web_sites do |ff|
I'm new to Rails and struggling to get my belongs_to association right. I have an app where a painting belongs to an artist and an artist can have_many paintings. I can create and edit my paintings, however I can not edit or create artists except through the console. Through much Googling I feel I have got myself turned around. Any help would be much appreciated!
Here's my routes.rb file:
MuseumApp::Application.routes.draw do
resources :paintings
resources :paintings do
resources :artists
resources :museums
end
root 'paintings#index'
end
Here's my paintings Controller
def show
#painting = Painting.find params[:id]
end
def new
#painting = Painting.new
##artist = Artist.new
end
def create
safe_painting_params = params.require(:painting).permit(:title, :image)
#painting = Painting.new safe_painting_params
if #painting.save
redirect_to #painting
else
render :new
end
end
def destroy
#painting = Painting.find(params[:id])
#painting.destroy
redirect_to action: :index
end
def edit
#painting = Painting.find(params[:id])
end
def update
#painting = Painting.find(params[:id])
if #painting.update_attributes(params[:painting].permit(:title, :image)) #safe_params
redirect_to #painting
else
render :edit
end
end
Here's the form in my paintings view:
<%= form_for(#painting) do |f| %>
<fieldset>
<legend>painting</legend>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.text_field :image %>
</div>
<%= form_for([#painting,#painting.create_artist]) do |f| %>
<div>
<%= f.label :Artist %>
<%= f.text_field :name %>
</div>
</fieldset>
<%= f.submit %>
<% end %>
<% end %>
Artists Controller:
class ArtistsController < ApplicationController
def index
#artists = Artist.all
#artists = params[:q] ? Artist.search_for(params[:q]) : Artist.all
end
def show
#artist = Artist.find params[:id]
end
def new
#artist = Artist.new
end
def create
#painting = Painting.find(params[:painting_id])
#artist = #painting.create_artist(artist_params)
redirect_to painting_path(#painting)
end
def destroy
#artist = Artist.find(params[:id])
#Artist.destroy
redirect_to action: :index
end
def edit
#artist = Artist.find(params[:id])
end
def update
#painting = Painting.find(params[:painting_id])
#artist = #artist.update_attributes(artist_params)
redirect_to painting_path(#painting)
end
end
private
def artist_params
params.require(:artist).permit(:name)
end
Index view:
<h1> Hello and Welcome to Museum App</h1>
<h3><%= link_to "+ Add To Your Collection", new_painting_artist_path %></h3>
<%= form_tag '/', method: :get do %>
<%= search_field_tag :q, params[:q] %>
<%= submit_tag "Search" %>
<% end %>
<br>
<div id="paintings">
<ul>
<% #paintings.each do |painting| %>
<li><%= link_to painting.title, {action: :show, id:painting.id} %> by <%= painting.artist_name %></li>
<div id = "img">
<br><%= link_to (image_tag painting.image), painting.image %><br>
</div>
<%= link_to "Edit", edit_painting_path(id: painting.id) %>
||
<%= link_to 'Destroy', {action: :destroy, id: painting.id},method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</ul>
</div>
In your case you should use accepts_nested_attributes_for and fields_for to achieve this.
Artist
has_many :paintings, :dependent => :destroy
accepts_nested_attributes_for :paintings
Painting
belongs_to :artist
And also you should try creating artist with paintings like this
form_for(#artist) do |f| %>
<fieldset>
<legend>Artist</legend>
<%= f.label :Artist %>
<%= f.text_field :name %>
<%= fields_for :paintings, #artist.paintings do |artist_paintings| %>
<%= artist_paintings.label :title %>
<%= artist_paintings.text_field :title %>
<%= artist_paintings.label :image %>
<%= artsist_paintings.text_field :image %>
</fieldset>
<%= f.submit %>
<% end %>
Note:
You should be having your Artist Controller with at least new,create,edit and update methods defined in it to achieve this.
Edit
Try the reverse
Artist
has_many :paintings, :dependent => :destroy
Painting
belongs_to :artist
accepts_nested_attributes_for :paintings
form_for(#painting) do |f| %>
<fieldset>
<legend>Painting</legend>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.text_field :image %>
<%= fields_for :artists, #painting.artists do |ff| %>
<%= ff.label :Artist %>
<%= ff.text_field :name %>
</fieldset>
<%= f.submit %>
<% end %>
Put this form in paintings views.
I'm getting this error:
Can't mass-assign protected attributes: quantities
I looked up all the threads concerning this issue in the site, but couldn't find something to answer my problem. Here are the code snippets:
product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :quantities_attributes
has_many :quantities
accepts_nested_attributes_for :quantities, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
new.html.erb
<% if #was_submitted %>
<%= form_for(:new_product_array, :url => products_path) do |f| %>
<% prefix ||= 0 %>
<% #new_product_array.each do |n| %>
<% n.quantities.build %>
<% prefix += 1 %>
<%= f.fields_for(prefix.to_s ) do |child| %>
<div class="field">
<%= child.label :name %><br />
<%= child.text_field :name%>
</div>
<%= render :partial => 'quantities/form',
:locals => {:form => child} %>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag :submit %>
</div>
<% end %>
<% else %>
<%= form_tag new_product_path, :method => 'get' do %>
<p align=center>
How many Items are you Adding? (1-100)
<%= number_field_tag 'amount', 1, :in => 1...100 %>
</br>
To which storage?
<%= number_field_tag 'storage', 1, :in => 1...100 %>
<%= submit_tag "Next", :name => 'submitted' %>
</p>
<% end %>
<% end %>
<%= link_to 'Back', products_path %>
product_controller.rb
def new
#product = Product.new
if params['submitted']
#was_submitted = true
#amount_form = params['amount']
#new_product_array = []
(1..#amount_form.to_i).each do
#new_product_array << Product.new
end
#storage_form = params['storage']
else
#was_submitted = false
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #product }
end
end
def create
i=0
logger.info params[:new_product_array].inspect
params[:new_product_array].each do |new_product|
if new_product.last[:name] != nil
#new_product_array[i] = Product.new(new_product.last)
#new_product_array[i].save
i+=1
end
end
redirect_to(products_path)
end
quantity.rb
class Quantity < ActiveRecord::Base
belongs_to :product
attr_accessible :amount, :storage
end
quantity/_form.html.erb
<%= form.fields_for :quantities do |quant| %>
<div class="field">
<%= quant.label :storage %><br />
<%= quant.number_field :storage %>
</div>
<div class="field">
<%= quant.label :amount %><br />
<%= quant.number_field :amount %>
</div>
<% unless quant.object.nil? || quant.object.new_record? %>
<div class="field">
<%= quant.label :_destroy, 'Remove:' %>
<%= quant.check_box :_destroy %>
</div>
<% end %>
<% end %>
Overall what Im trying to do, is ask the user how much products to add, then make a form with the number of fields the user specifies and with one submit button add all of the products, whereas when you add a product you also add a quantity record which holds more information on the product.
You need a line like this:
attr_accessible :name, :quantities_attributes, :quantities
You have very bad code, it can be much simplier 100%.
Your problem is that form dont' know nothing about your resource (product), so it can't render 'smartly' fields "quantities_attributes", it renders "quantities" instead.
I know how to build the 2nd object in a controller but how do you build a third or a fourth?
In my case i need to build 3.
Location - has_many :product_dates, :products
ProductDate - has_many :products & belongs_to :location
Product - belongs_to :location, :product_date
I build the Location and Product Date easily:
def new
#location = Location.new
#location.product_dates.build
end
Now i need to build the products on the form. Can anyone show me how to do this?
EDIT: Complete Answer:
def new
#location = Location.new
product_date = #location.product_dates.build
product_date.products.build
end
<%= form_for #location do |f| %>
<%= f.text_field :business %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates do |date| %>
<%= date.date_select :date %>
<%= date.fields_for :products do |product| %>
<%= product.text_field :name %>
<%= product.text_field :price %>
<%= product.text_field :tag_list %>
<% end %>
<% end %>
<%= f.submit "Create" %>
<% end %>
You'll learn everything in video here.
EDIT:
change the nested part with:
<%= f.fields_for :product_dates do |date| %>
<%= date.date_select :date %>
<%= date.fields_for :products do |product| %>
<%= product.text_field :name %>
<%= product.text_field :price %>
<%= product.text_field :tag_list %>
<% end %>
<% end %>
Because products are nested inside product_dates
add to your controller:
def new
#location = Location.new
#product_dates = #location.product_dates.build
#product = #product_dates.product.build
end
in you ProductDate model:
class ProductDate < ActiveRecord::Base
accepts_nested_attributes_for :products
...
in you Location model:
class Location < ActiveRecord::Base
accepts_nested_attributes_for :product_dates
...
And you form should be like this:
<% f.fields_for :product_dates do |date| %>
<%= date.text_field :content %>
<% date.fields_for :products do |product| %>
<%= product.text_field :content %>
<%end %>
<% end %>
I'm trying to implement master detail in a rails form with fields_for.
I have one model called Recipe:
class Recipe < ActiveRecord::Base
validates :name, :presence => true
validates :directions, :presence => true
has_many :recipe_ingredients
end
and one model called RecipeIngredient:
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe
#belongs_to :ingredient
end
In the new controller I populate the ingredients with three empty records like this:
def new
#recipe = Recipe.new
3.times {#recipe.recipe_ingredients.build}
# #ingredients = RecipeIngredient.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #recipe }
end
end
What I would like to do in the view is to output the recipes fields (which works ok) and the three fields for recipe ingredients. In the top part of the view I have this:
<%= form_for :rec do |f| %>
I then list the recipe fields which are displayed correctly, like:
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
I then try to display the ingredient lines but the code never seems to go into the fields_for section:
first try:
<% for ingredient in #recipe.recipe_ingredients %>
This prints out three times
<% fields_for "...", ingredient do |ingredient_form| %>
But this never prints out
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end%>
I have three empty lines in recipe_ingredients and the for loop seems to iterate three times but the code within fields_for never triggers.
Second try:
<% for recipe_ingredient in #recipe.recipe_ingredients %>
b
<% fields_for "...", recipe_ingredient do |recipe_ingredient| %>
Rec: <%= recipe_ingredient.text_field :description %>
<% end %>
<% end %>
Third try (based on the answer here):
<% form_for :recipe do |f| %>
<% f.fields_for ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>
Is there something obvious I'm doing wrong?
You should use <%= instead of <% when using form_for and fields_for
The correct code should look like this:
<%= form_for :recipe do |f| %>
<%= f.fields_for :ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>
Switch it up to
<% form_for :recipe do |f| %>
<% f.fields_for :ingredients do |ingredient_form| %>
<p>
Ingredient: <%= ingredient_form.text_field :description %>
</p>
<% end %>
<% end %>