I use accepts_nested_attributes_for in a model but my child form isn't saved in the database?
I am building a nested form almost in the same way as in episode 196 / 197 from Ryan Bates railscasts. I have a parent question form and as a child the answer form:
models/question.rb
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:text].blank? },
:allow_destroy => true
validates :content, :presence => true
end
models/answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
end
controllers/questions_controller.rb
class QuestionsController < ApplicationController
before_filter :authenticate_user!
def index
setup_questions
end
def create
#question = Question.new(params[:question])
#this is to get every id_key from the user into the params of the answer
params[:question][:answers_attributes].keys.each {|key| params[:question][:answers_attributes][key][:user_id] = current_user.id }
#question.user_id = current_user.id
if #question.save
redirect_to questions_path, :notice => "Successfully created question."
else
setup_questions
render :index
end
end
def edit
#question = Question.find(params[:id])
end
def update
#question = Question.find(params[:id])
respond_to do |format|
if #question.update_attributes(params[:question])
format.html { redirect_to(#question, :notice => 'Question was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #question.errors, :status => :unprocessable_entity }
end
end
end
def show
#question = Question.find(params[:id])
end
def destroy
#question = Question.find(params[:id])
#authorize! :destroy, #question
#question.destroy
redirect_to questions_path, :notice => "Successfully deleted question: #{#question.content}."
end
private
def setup_questions
#questions = Question.all
#question ||= Question.new
#question.answers.build #to build the answers form
end
end
views/question/_form.html.erb
<%= form_for(#question) do |f| %>
<!-- =================== -->
<!-- = Error handeling = -->
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<!-- =================== -->
<!-- ================= -->
<!-- = Question form = -->
<div class="field">
<%= f.label :content, "Question" %><br />
<%= f.text_field :content, :placeholder => "type your question here.." %>
</div>
<!-- ====================== -->
<!-- = Nested Answer form = -->
<div class="answer-field">
<%= f.fields_for :answers do |builder| %>
<%= builder.label :content, "Possible answer" %><br />
<%= builder.text_field :content, :placeholder => "type an optional answer.." %>
<% end %>
</div>
<!-- ====================== -->
<div class="actions">
<%= f.submit %>
</div>
<!-- ================= -->
<% end %>
So now the big question... Why doesn't it save anything from the answer field to the database? I thought one create action at the parent (question) should be enough and that the "accepts_nested_attributes_for" should take care of it's child(s).
Regards,
Thijs
1 Remove this line from controller
params[:question][:answers_attributes].keys.each {|key| params[:question][:answers_attributes][key][:user_id] = current_user.id }
2 add this into your view
<!-- = Nested Answer form = -->
<div class="answer-field">
<%= f.fields_for :answers do |builder| %>
<% builder.object.user = current_user %>
<%= builder.label :content, "Possible answer" %><br />
<%= builder.text_field :content, :placeholder => "type an optional answer.." %>
<%= builder.hidden_field, :user_id %>
<% end %>
</div>
<!-- ====================== -->
Related
While i was trying to submit the form, following error occured: Validation failed: Images imageable must exist and render the same new.html.erb view.
If i comment the file field in new.html.erb. Product is being created successfully.
ProductsController:
def new
#product = Product.new
end
def create
#product = Product.create!(product_params)
if #product.save
redirect_to products_path, notice: "Product Created Successfully"
else
render "new"
end
end
def product_params
params.require(:product).permit(:name, :quantity, :price, images_attributes: [:id, :photo, :_destroy])
end
new.html.erb:
<%= nested_form_for #product, html: { multipart: true } do |f|%>
<h2>New</h2>
<P> <%= f.label :name %> <%= f.text_field :name %> </P>
<P> <%= f.label :quantity %> <%= f.text_field :quantity %> </P>
<P> <%= f.label :price %> <%= f.text_field :price %> </P>
<%= f.fields_for :images do |p| %>
<p> <%= p.label :photo %> <%= p.file_field :photo %> </p>
<%= p.link_to_remove "Remove Image" %>
<% end %>
<%= f.link_to_add "Add Image", :images %>
<%= f.submit "Add Product" %>
<% end %>
20160725102038_add_image_columns_to_imageable.rb:
class AddImageColumnsToImageable < ActiveRecord::Migration[5.0]
def up
add_attachment :images, :photo
end
def down
remove_attachment :images, :photo
end
end
Model:product.rb
class Product < ApplicationRecord
has_one :variant
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
Model:image.rb
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
In rails 5, belongs_to makes sure that the associated model must exist.
E.g In this polymorphic association, Image model has belongs_to :imageable and Product model has has_many :images.
So here in new.html.erb we are creating an image, but respective product not exist, so that's why error Image imageable must exist .
Solution
Add optional: true while making an association of belong_to in Image model.
Image Model now looks like:
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true, optional: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
Can anybody please help me to resolve the following error using rails version-3.2.19 ?When i am submitting values to database this error is coming.
Error
ActiveModel::MassAssignmentSecurity::Error in UsersController#create
Can't mass-assign protected attributes: con_password
My code snippets are as follows.
views/users/new.html.erb
<center>
<h1>Enter your data</h1>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-div">
<%= form_for :user,:url => {:action => 'create'} do |f|%>
<p>
<%= f.label :Name %>
<%= f.text_field :name,placeholder:"Enter your name" %>
</p>
<p>
<%= f.label :Email %>
<%= f.email_field :email,placeholder:"Enter your Email" %>
</p>
<p>
<%= f.label :Password %>
<%= f.password_field :password,placeholder:"Enter your password" %>
</p>
<p>
<%= f.label :password %>
<%= f.password_field :con_password,placeholder:"Enter your password again" %>
</p>
<p>
<%= f.label :content %>
<%= f.text_field :content,placeholder:"Enter your content" %>
</p>
<p>
<%= f.submit "Create User",:class => 'submit' %>
</p>
<% end %>
</div>
</center>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def show
end
def create
#user=User.new(params[:user])
if #user.save
flash[:notice]="User has created successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="User could not create"
flash[:color]="invalid"
render :new
end
end
end
model/user.rb
class User < ActiveRecord::Base
attr_accessible :content, :email, :name, :password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :confirmation => true
validates_length_of :password, :in => 6..20, :on => :create
end
migrate\20150128062543_create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password
t.string :content
t.timestamps
end
end
end
Please help me to solve this issue.
Instead of <%= f.password_field :con_password,placeholder:"Enter your password again" %>, you should name your field password_confirmation, because this is what your model expects if it has validates :password, confirmation: true:
<%= f.password_field :password_confirmation, placeholder: "Enter your password again" %>
You also have to add password_confirmation to attr_accessible in the model.
Please anyone help me to resolve the following error.Actually I want to show the exit values those present in DB on the text field in edit page.But i am getting some error.
Error:
NoMethodError in Users#edit
Showing C:/Site/edit/app/views/users/edit.html.erb where line #4 raised:
undefined method `each' for #<User:0x3ac9ea8>
Below are my code snippets
views/users/index.html.erb:
<h1>This is index page</h1>
<center>
<p>Enter data</p>
<div class="option">
<p><%= link_to "Click here to enter data",users_new_path %></p>
<p><%= link_to "Display data",users_show_path%></p>
</div>
</center>
views/users/show.html.erb
<h1>Show your data</h1>
<center>
<ul>
<% #user.each do |t| %>
<li>
<%= t.name %> |
<%= t.email %> |
<%= t.password%> |
<%= t.created_at %>
<%= link_to "edit",users_edit_path(:id => t.id) %> || <%= link_to "Reset Password",users_reset_path(:id => t.id) %>
</li>
<% end %>
</ul>
<div class="back_btn">
<button type="button" class="btn-custom " style="cursor:pointer;">Back</button>
</div>
</center>
views/users/edit.html.erb
<h1>Edit your data here</h1>
<center>
<%= form_for #user ,:url => {:action => "update",:id => params[:id]} do |f| %>
<% #edit.each do |t| %>
<div class="div_reg">
<p>
<label for="username" class="uname" data-icon="u" >username </label>
<%= f.text_field:name, :input_html => {:value => t.name}%>
</p>
<p>
<label for="username" class="uname" data-icon="u" >Email </label>
<%= f.text_field:email,:input_html => {:value => t.email} %>
</p>
<p>
<label for="username" class="uname" data-icon="u" >Password </label>
<%= f.password_field:password,:input_html => {:value => t.password} %>
</p>
<p>
<label for="username" class="uname" data-icon="u" >Password </label>
<%= f.password_field :password_confirmation %>
</p>
<center>
<%= f.submit "Update",:class => 'btn-custom' %>
</center>
<div class="back_btn">
<button type="button" class="btn-custom " style="cursor:pointer;">Back</button>
</div>
</div>
<% end %>
<% end %>
</center>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li><%= message_error %></li>
<% end %>
</ul>
<% end %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_param);
if #user.save
flash[:notice]="You signed up successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You have not signed up successfully"
flash[:color]="invalid"
redirect_to :action => 'new'
end
end
def show
#user=User.all
end
def edit
#user=User.new
#edit=User.find(params[:id])
end
def update
flash[:notice]=params[:id]
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data is updated succesfully"
flash[:color]="valid"
redirect_to :action => 'show'
else
flash[:alert]="Your data could not update,Please check it..!!"
flash[:color]="invalid"
redirect_to :action => 'edit'
end
end
def reset
#user=User.new
end
def emailsend
#user=User.find(params[:id])
if #user.email== params[:user][:email]
UserMailer.registration_confirmation(#user).deliver
flash[:notice]="Check your email to reset the password"
flash[:color]="valid"
redirect_to :action => 'reset'
else
flash[:notice]="Check your valid email or your email is not found"
flash[:color]="invalid"
redirect_to :action => 'show'
end
end
def resetpass
#user=User.new
end
def passres
#user=User.find_by_email(params[:user][:email])
if #user.update_attributes(updates_password)
flash[:notice]="Your password id updated succefully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..Please check it..!!"
flash[:color]="invalid"
redirect_to :action => 'show'
end
end
private
def users_param
params.require(:user).permit(:name, :email, :password,:password_confirmation)
end
def update_params
params.require(:user).permit(:name,:email,:password,:password_confirmation)
end
def updates_password
params.require(:user).permit(:email,:password,:password_confirmation)
end
end
model/user.rb
class User < ActiveRecord::Base
#attr_accessor :password
#attr_accessor :name
#attr_accessor :email
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :confirmation => true
validates_length_of :password, :in => 6..20, :on => :create
end
Please help me to resolve this error.Thanks in advance.
#edit.each is your problem. You have a User instance here not an ActiveRecord array of Users therefore .each isn't available.
You can remove the iteration <% #edit.each do |t| %> and change all references t to #edit ie. #edit.name.
I want to modify the action (submit) for a form_for helper
<%= form_for(#rating, :as => :post, :url => demo_create_rating_path(#rating)) do |f| %>
<div class="field">
<%= f.label :value %><br />
<%= f.select :value, %w(1 2 3 4 5) %>
</div>
<%= f.hidden_field :article_id, :value => #article.id%>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description, size: "100x5" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is my View and it does not work.
All I want is, that I can redirekt the Action after submit button but then a get this error:
ActionController::RoutingError (No route matches {:controller=>"demo_ratings", :action=>"create", :article_id=>#<Rating id: nil, value: nil, description: nil, article_id: nil, user_id: nil, created_at: nil, updated_at: nil>}):
app/views/demo_ratings/_form.html.erb:1:in `_app_views_demo_ratings__form_html_erb__1912848844925280312_70155649546120'
app/views/demo_ratings/new.html.erb:13:in `_app_views_demo_ratings_new_html_erb__27525029454473720_70155632487040'
What am I doing wrong?
UPDATE
All my funktion that are need by form_for helper:
def new
#rating = Rating.new
#article = Article.find(params[:article_id])
end
def edit
#rating = Rating.find(params[:id])
#article = Article.find(params[:article_id])
end
def create
#rating = Rating.new(params[:rating])
if #rating.save
#article= Article.find(params[:article_id])
puts #article.name
puts #rating.id
#rating.article = #article
puts #rating.article.name
redirect_to demo_rating_path(#rating, :article_id => #article.id), notice: 'Rating was successfully created.'
else
render action: "new"
end
end
def update
#rating = Rating.find(params[:id])
if #rating.update_attributes(params[:rating])
#article = #rating.article
redirect_to demo_rating_path(#rating), notice: 'Rating was successfully updated.'
else
render action: "edit"
end
end
Try this:
<%= form_for(#rating, :as => :post, :url => demo_create_rating_path) do |f| %>
The #rating in the url is providing a nil object id, and you don't have an id yet.
If you want to share the form between create and update, then use the following:
<% form_for(#rating, :as => :post) do |f| %>
For reference, review the output of a rails generated scaffold's _form.html.erb.
In your controller, your are saving the new/ updated record before your processing. The statement if #rating.save should come after #rating.article = #article.
def create
#rating = Rating.new(params[:post])
#article= Article.find(params[:article_id])
#rating.article_id = #article.id
if #rating.save
redirect_to demo_rating_path(#rating, :article_id => #article.id), notice: 'Rating was successfully created.'
else
render action: "new"
end
end
I am trying to make available to upload a multiple pictures with paperclip. I am following this tutorial: http://www.emersonlackey.com/article/paperclip-with-rails-3
Unfortunately I have error:
No handler found for "apple_mac-1280x800.jpg"
Asset.rb
class Asset < ActiveRecord::Base
belongs_to :post
has_attached_file :asset, :styles => { :small => "100x100", :original => '800x600>'}
end
Post.rb
class Post < ActiveRecord::Base
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
end
Posts_controller.rb
def new
#post = Post.new
5.times { #post.assets.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
def edit
#post = Post.find(params[:id])
5.times { #post.assets.build }
end
#Post form
<% create_url = {:url=>{:action=>"create"}} if #post.new_record? %>
<% form_for #post, :html => {:multipart => true} do |t| %>
<p>
<%= t.label :title, 'Virsraksts:' %>
<%= t.text_field :title %>
</p>
<p>
<%= t.label :content, 'Teksts:' %>
<%= t.text_area :content, :class => "mceEditor"%>
</p>
<%= t.fields_for :assets do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<p>
<%= asset_fields.file_field :asset %>
</p>
<% end %>
<% end %>
<%= t.submit %>
<% end %>
<%end%>
Problem solved by changing
<%= t.fields_for :assets do |asset_fields| %>
to
<%= f.fields_for :assets do |asset_fields| %>
But could someone explain why?