What is the proper way to have a form in a partial view reference an empty model in order to handle validation properly as defined on the model. Should I instantiate a new, empty model in the partial view and pass it through to the form? Here is what I'm working with...
MODEL
class NewsletterSignup < ActiveRecord::Base
def self.columns()
#columns ||= [];
end
def self.column(name, sql_type = nil, default = nil, null = false)
columns << ActiveRecord::ConnectionAdapters::Column.new(name, default, sql_type, null)
end
def persisted?
false
end
column :first_name, :string
column :last_name, :string
column :email, :string
column :zip, :string
validates :first_name, :last_name, :email, :zip, :presence => true
validates :email, :format => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates :zip, :format => /^\d{5}$/
end
Partial View
<%
signup = newsletter_signup.new
%>
<%= simple_form_for(signup, ...) do |f| %>
<%= f.input :first_name, :label => "First Name:" %>
<%= f.input :last_name, :label => "Last Name:" %>
<%= f.input :email, :label => "Email:" %>
<%= f.input :zip, :label => "Zip:" %>
...
<% end %>
But I can't seem to instantiate a new model like this. I assume I have to reference it in the view. (Note, I'm new to rails but have a decade+ of professional software development experience, so I apologize if some of rails constructs seem foreign to me and I may just be overlooking something simple!)
If your controller looks like this
def new
Model.new
end
def create
#model = Model.new(params[:model])
if #model.save
redirect root_path, notice: "Saved"
else
render action: 'new'
end
end
def edit
Model.find(params[:id])
end
def update
if #model.update(params[:model])
redirect root_path, notice: "Updated"
else
render action: 'edit'
end
end
You can have views like:
# new.html.erb
<%= render 'form' %>
# edit.html.erb
<%= render 'form' %>
# _form.html.erb
<%= form_for #model do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
...
<% end %>
Related
Form helper collection_check_boxes returns data as an array, but how to put it into mysql database (or into variable in the controller)?
In my controller I have
def new
#subjects = Subject.all
#student = Student.new(:first_name => "First name", :last_name => "Last name", :birthdate => "Birthday", :email => "E-mail", :phone_number => "Phone number", :classes)
end
def create
#student = Student.new(student_params)
if #student.save
redirect_to(students_path)
else
render('new')
end
end
private
def student_params
params.require(:student).permit(:first_name, :last_name, :birthdate, :email, :phone_number, :classes)
end
Form looks like this:
<%= form_for(#student) do |f| %>
<%= f.collection_check_boxes :classes, Subject.all, :id, :subject %>
<%= f.submit("Create student") %>
<% end %>
I'm using nested attributes to user adresses.
class User < ApplicationRecord
accepts_nested_attributes_for :address, update_only: :true
I'm passing the address id as hidden field at sign-in.
<%= form_for (#user), :html => {:class => 'lead-form'} do |f| %>
<%= f.email_field :email, class:'form-control', placeholder: "Email", required: true %>
<%= f.password_field :password, class:'form-control', placeholder: "Senha", required: true %>
<%= f.fields_for :address do |addresses_form| %>
<%= addresses_form.hidden_field :address_id, :value => #address.id %>
<% end %>
<%= f.submit 'Pedir meu convite', class: "button lead-form-button" %>
<% end %>
The e-mail is validate as uniqueness. So, when somebody try to sign in with an already taken e-mail the address params are passed as nil and i get the error:
NoMethodError in Users#create
undefined method `id' for nil:NilClass
Any idea how can i fix that?
Here is my controller:
def new
#user = User.new
#address = #user.build_address
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Você está dentro. Esse é seu perfil! =) "
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:id, :primeiro_nome, :sobrenome, :email, :cpf, :telefone, :sexo, :data_de_nascimento, :password, address_attributes: [:id, :logradouro, :bairro, :cidade, :uf, :complemento, :cep])
end
ps: The association is one to one. How can i call the address attributes if i don't pass as hidden.
Address belongs to user? If yes, you just call #user.address
Maybe you should try using try method:
<%= addresses_form.hidden_field :address_id, :value => #address.try(:id) %>
I am creating a nested form with attributes from different models. I expect all the required attributes to be valid, before a new object is saved.
<%= form for #product do |f| %>
<%= f.fields_for #customer do |g| %>
<%= g.label :name %>
<%= g.text_field :name %>
<%= g.label :email %>
<%= g.text_field :email %>
<%= g.label :city %>
<%= g.text_field :city %>
<%= g.label :state %>
<%= g.text_field :state %>
<%= g.label :zipcode %>
<%= g.text_field :zipcode %>
<% end %>
<%= f.label :product %>
<%= f.text_field :product %>
<%= f.label :quantity %>
<%= number_field(:quantity, in 1..10) %>
<% end %>
Here are my models
class Product < ActiveRecord::Base
belongs_to :customer
validates_associated :customer
validates :product, :presence => "true"
end
class Customer < ActiveRecord::Base
has_one :product
validates :name, :email, presence: true
validates :email, format: { with: /[A-Za-z\d+][#][A-Za-z\d+][.][A-Za-z]{2,20}\z/ }
validates :city, presence: true
validates :zipcode, format: { with: /\A\d{5}\z/ }
end
I added validates_associated to my Product Model, so my form_for #product should require all the customer validations to pass. That means name, email, city and zipcode have to be there and have to be formatted properly.
I fiddled around, and submitted the form without filling in the Customer required fields, and the form was considered valid.
I don't understand where my mistake is.
EDIT
Alright, so by adding validates :customer, the customer attributes are now required. But they aren't actually saved to the database. I think this has to do with my params
def product_params
params.require(:product).permit(:product, :quantity)
end
Do I need to add my Customer Params to my permitted params list?
The validates_associated method only validates the associated object if the object exists, so if you leave the form fields blank, the Product you are creating/editing will validate, because there is no associated Customer.
Instead, assuming you're using Rails 4+, you want to use accepts_nested_attributes_for :customer, along with validates :customer, presence: true in order to required the customer fields in your product form.
If you're using Rails 3, then accepts_nested_attributes_for will not work for a belongs_to association. Instead, your Customer class will need to use accepts_nested_attributes_for :product, and you will need to alter your form view accordingly.
UPDATE
You also need to allow your controller action to accept parameters for the :customer association:
def product_params
params.require(:product).permit(:product, :quantity, :customer_attributes => [:name, :email, :city, :state, :zipcode])
end
It's worth noting that because there is no :id field in your customer form fields, and no :customer_id field in your product form fields, you will create a new customer every time you successfully submit the product form.
try this out:
In Controller create an instance of a product and associated customer as follows:
#product = Product.new
#customer = #product.build_customer
in use this code for form
<%= form for #product do |f| %>
<%= f.fields_for :customer do |g| %>
<%= g.label :name %>
<%= g.text_field :name %>
<%= g.label :email %>
<%= g.text_field :email %>
<%= g.label :city %>
<%= g.text_field :city %>
<%= g.label :state %>
<%= g.text_field :state %>
<%= g.label :zipcode %>
<%= g.text_field :zipcode %>
<% end %>
<%= f.label :product %>
<%= f.text_field :product %>
<%= f.label :quantity %>
<%= number_field(:quantity, in 1..10) %>
<% end %>
i.e use :customer symbol instead of #customer instance variable.
and use accepts_nested_attributes_for helper method in Product model as #Charles said
Complementing the other answers, I control what I receive in the controller, avoiding further action and noticing if a value is not the one I want.
def update
if params[:customer][:product_attributes]["0"][:name] == ""
redirect_to customer_path(#incident), alert: 'You need to add a name'
else
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to customer_path(#customer), notice: 'Succesfully updated' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
end
I have the below contact form and I would like to allow customers to send me an image as an attachment. I have added the field to the form but don't understand the following -
What migration do I create?
How do I attach the image to the
mailer?
View
<%= simple_form_for #inquiry, :method => :post do |f| %>
<%= f.input :spam, as: :hidden %>
<%= f.input :name %>
<%= f.input :phone %>
<%= f.input :email %>
<%= f.input :message %>
<%= f.file_field :image %> ## Attachment input here
<%= f.button :submit, 'Send' %>
<% end %>
Controller
def new
#inquiry = Inquiry.new
end
def create
redirect_to new_inquiry_path and return if params[:spam].present?
#inquiry = Inquiry.new(inquiry_params)
if #inquiry.valid?
InquiryMailer.admin(#inquiry).deliver
redirect_to inquiries_path
else
render :new
end
end
private
def inquiry_params
params.require(:inquiry).permit(:name, :email, :phone, :message)
end
Model
validates :name, presence: true
validates :email, presence: true
validates :phone, presence: true
validates :message, presence: true
inquiry_mailer.rb
class InquiryMailer < ActionMailer::Base
default from: "noreply#foo.com"
def admin(inquiry)
#inquiry = inquiry
mail to: "hello#foo.co.uk", subject: "Website Inquiry"
end
end
admin.text.erb
Website Inquiry
=========
Name: <%= #inquiry.name %>
Phone: <%= #inquiry.name %>
E-Mail: <%= #inquiry.email %>
Message: <%= #inquiry.message %>
You can make use of ActionMailer here
Ill provide an answer based upon your existing setup
You need to edit your mailer to look something like this
class InquiryMailer < ActionMailer::Base
default from: ENV['EMAIL_ADDRESS'] #I like to keep my email address hidden
def admin(inquiry)
#inquiry= inquiry
if inquiry.file
attachment_name = inquiry.file.original_filename
attachments[attachment_name] = inquiry.file.read
end
mail(to: ENV['EMAIL_ADDRESS'], subject: 'Website Inquiry')
end
end
You can keep admin.text.erb as it is and your controller stays the same
and within your form_for dont forget to add
<%= simple_form_for #inquiry, :method => :post, :multipart => true do |f| %>
so you the attachment can be added
Think thats it off the top of my head
Hope that helps, any questions then please ask
everyone
I have two simple models with embedded one to one relation.
class Employee
include Mongoid::Document
field :first_name, type: String
field :last_name, type: String
embeds_one :empdate
accepts_nested_attributes_for :empdate
end
class Empdate
include Mongoid::Document
field :hiring_date, type: String
field :prob_expire, type: String
embedded_in :employee, :inverse_of => :empdate
end
with the controller methods
def new
#employee = Employee.new
#employee.build_empdate
end
def create
#employee = Employee.new(params.require(:employee).permit(:first_name, :last_name, :empdate_attributes))
if #employee.save
redirect_to employees_path
else
render 'new'
end
end
and the form for the new employee
<%= form_for #employee do |f| %>
<%= f.label :first_name, 'First Name:' %>
<%= f.text_field :first_name %>
<br />
<%= f.fields_for :empdate do |d| %>
<%= d.label :hiring_date, 'Hiring Date:' %>
<%= d.text_field :hiring_date %>
<% end %>
<%= submit_tag 'submit' %>
<% end %>
After submit, only employee info is saved, but not dates. Can anyone help me with identifying errors ?
change create method first line to
#employee = Employee.new(params.require(:employee).permit(:first_name, :last_name, :empdate_attributes => [:hiring_date]))