I have the following form validations for name and email:
validates :name, presence: true
validates :email, presence: true
In my browser it looks like:
But, when I submit the following form:
= simple_form_for #contact, :url => create_enquiry_path, :method => :post do |form|
= form.input :name
= form.input :email
= form.input :phone
= form.input :website
There are no errors on the page, but I get:
param is missing or the value is empty for: contact
My controller is:
def create
#contact = ContactForm.new(form_params)
if #contact.errors.any?
render :action => :new
flash[:error] = 'Please correct errors.'
else
redirect_to ....
flash[:notice] = 'Thank you for your message. We will contact you soon!'
end
private
def form_params
params.require(:contact).permit(:name, :phone, :email, :website)
end
Could someone please explain what I am doing wrong here?
It appears that your parameters dictionary is structured differently than you're expecting. If your params dictionary is coming to your controller like:
{ :name => 'John', :email => 'john.smith#abc.ca', ...... }
Then change your form_params method to:
def form_params
params.permit(:name, :phone, :email, :website)
end
If your params dictionary is coming to your controller like:
{ :contact_form => { :name => 'John', :email => 'john.smith#abc.ca', ...... } }
Then change your form_params method to (based on #JiříPospíšil's suggestion):
def form_params
params.require(:contact_form).permit(:name, :phone, :email, :website)
end
If the name of the model is ContactForm, then form_params should reference :contact_form, not :contact.
Related
I have working mail_form contact form with google's smtp service.
I satisfied almost with everything, but form not showing errors for invalid email.
There is an error appears if email field is blank, but if something present in the field and you press "Send message" button nothing happens - validation not allowing send message, but user not informed that something wrong.
contact.rb
class Contact < MailForm::Base
attribute :name
attribute :email, validate: URI::MailTo::EMAIL_REGEXP
attribute :message, validate: true
attribute :file, attachment: true
def headers
{
subject: "My Contact Form",
to: 'MYEMAIL#gmail.com',
from: %("#{name}" <#{email}>)
}
end
end
views/contacts/new.html.haml
= form_with model: #contact do |f|
= f.label :name
= f.text_field :name, required: true, class: "text-field"
= f.label :email
= f.text_field :email, required: true, class: "text-field", placeholder: "email#example.com"
= f.label :message
= f.text_area :message, rows: 6, required: true, class: "text-field"
= f.label :files, class: "inline-block p-1 pt-2"
= f.file_field :file, class: "block p-1 font-body text-sm"
= f.submit t('send_message'), class: "submit"
contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
#contact.request = request
if #contact.deliver
redirect_to contacts_path, notice: 'Message sent!'
else
flash.now[:error] = 'Could not send message'
render :new
end
end
private
def contact_params
params.require(:contact).permit(:name, :email, :message, :file)
end
end
I have tried many things to show error messages, which have worked in my previous projects, but can't make it work with mail_form contact form.
I have written the following to accept roles ,how can make it accept multiple values
= f.simple_fields_for :content_roles do |role|
= role.input :role_id, label: "visible to", as: :select, label: "Role", collection: Role.all, required: true
Just add multiple: true to your role field.
Like this:
= role.input :role_id, label: "visible to", as: :select, label: "Role", collection: Role.all, required: true, multiple: true
This is the code that is working in my current online project. Updated missing ruby tag....
the following worked for me without fields_for and it should only be used when you have to add a new role in my opinion
you can just do this with preselect values and bootstrap selectpicker:
= simple_form_for [:backend, #user], html: { autocomplete: 'off' } do |f|
= f.select :role_ids, options_for_select(Role.all.map{|role| [role.name, role.id]}, #user.role_ids), {}, {:multiple => true, inlcude_blank: false, class: "form-control input-sm selectpicker"}
controler:
module Backend
class UsersController < ApplicationController
before_action :set_user, only: %i[edit update]
def index
#users = User.all
end
def edit
#user.roles.build unless #user.roles.any?
end
def update
if #user.update user_params
redirect_to backend_users_path(#user), notice: 'Rollen erfolgreich aktualisiert'
else
render :edit
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:id, role_ids: [])
end
end
end
I am new to Rails. Getting the error below. I understand what the issue is, but not sure how to fix it?
Error - param is missing or the value is empty: customer
def customer_params
params.require(:customer).permit(
:first_name,
:last_name,
:email,
:password,
:password_confirmation)
end
end
DetailsController.rb
class My::Account::DetailsController < MyController
def show
#customer = current_user
end
def update
#customer = current_user
#customer.update_attributes(customer_params)
if #customer.errors.any?
render :action => :show
else
redirect_to my_account_details_path, :notice => 'Account details updated'
end
end
private
def customer_params
params.require(:customer).permit(
:first_name,
:last_name,
:email,
:password,
:password_confirmation)
end
end
View
.account.container
.row
= render :partial => '/my/account/sidebar'
.section
%h2 Your account details
= simple_form_for #customer, :url => my_account_details_path, :method => :put, :html => { :class => 'form-horizontal'} do |form|
.field
= form.input :first_name
.field
= form.input :last_name
.field
= form.input :email, :as => :email
%hr
%h4 Leave password fields blank to keep the existing password
%hr
.field
= form.input :password, :input_html => { :value => '' }
.field
= form.input :password_confirmation, :input_html => { :value => '' }
.field-actions
%button.btn.btn-primary{type: "submit"} Save
It is because it is coming through as user and not customer. Which I believe is because you are using current_user which is a User and not a Customer (guessing from the code). Change it to be params.require(:user).permit(blah)
I'm getting this really weird error when I submit my nested form.
Can't mass-assign protected attributes: _destroy
Any idea why this may be? It's a bit of a concern as I'm having to remove the 'destroy' hidden_field with javascript temporarily until i figure out what it is, meaning i can't delete anything!
_form.html.erb
<%= nested_form_for(#post, :html=> {:multipart => true, :class=> "new_blog_post", :id=> "new_blog_post"}) do |f| %>
<%= field do %>
<%= f.text_field :title, placeholder: "Give your post a title", :class=>"span12" %>
<% end %>
<%= field do %>
<%= f.text_area :body, placeholder: "Write something here...", :id=>"blog-text", :class=>"span12" %>
<% end %>
<%= f.label :search_locations, "Add locations to your post" %>
<%= text_field_tag :name,"",:class=>"localename", :id=>"appendedInput", :placeholder=> "Name of the location", :autocomplete => "off" %>
<%= f.link_to_add "Add a location", :locations %>
<%= actions do %>
<%= f.submit "Submit", :class=>"btn", :disable_with => 'Uploading Image...' %>
<% end end%>
_posts_controller.rb_
class PostsController < ::Blogit::ApplicationController
...
def new
#post = current_blogger.blog_posts.new(params[:post])
#location = #post.locations.build
end
def edit
#post = Post.find(params[:id])
##post = current_blogger.blog_posts.find(params[:id]) removed so any use can edit any post
#location = #post.locations.build
end
def create
location_set = params[:post].delete(:locations_attributes) unless params[:post][:locations_attributes].blank?
#post = current_blogger.blog_posts.new(params[:post])
#post.locations = Location.find_or_initialize_location_set(location_set) unless location_set.nil?
if #post.save
redirect_to #post, notice: 'Blog post was successfully created.'
else
render action: "new"
end
end
def update
#post = current_blogger.blog_posts.find(params[:id])
if #post.update_attributes(params[:post])
redirect_to #post, notice: 'Blog post was successfully updated.'
else
render action: "edit"
end
end
def destroy
#post = current_blogger.blog_posts.find(params[:id])
#post.destroy
redirect_to posts_url, notice: "Blog post was successfully destroyed."
end
location.rb
class Location < ActiveRecord::Base
after_save { |location| location.destroy if location.name.blank? }
has_many :location_post
has_many :posts, :through => :location_post
has_many :assets
attr_accessible :latitude, :longitude, :name, :post_id, :notes, :asset, :assets_attributes
accepts_nested_attributes_for :assets, :allow_destroy => true
include Rails.application.routes.url_helpers
def self.find_or_initialize_location_set(location_set)
locations = []
locations = locations.delete_if { |elem| elem.flatten.empty? }
location_set.each do |key, location|
locations << find_or_initialize_by_name(location)
end
locations
end
end
EDIT:
Snippet of rendered form in new.html.erb
<div class="row span locsearch">
<div class="input-append span3">
<input autocomplete="off" class="localename" id="appendedInput" name="name" placeholder="Name of the location" type="text" value="">
<span class="add-on"><input id="post_locations_attributes_0__destroy" name="post[locations_attributes][0][_destroy]" type="hidden" value="false"><i class="icon-trash"></i></span> </div>
<div class="latlong offset3 span4"> <p class="help-block">Enter the name of the town or city visited in this blog entry.</p>
</div>
<input class="LegNm" id="post_locations_attributes_0_name" name="post[locations_attributes][0][name]" type="hidden" value="Dresden">
<input class="long" id="post_locations_attributes_0_longitude" name="post[locations_attributes][0][longitude]" type="hidden" value="13.7372621">
<input class="lat" id="post_locations_attributes_0_latitude" name="post[locations_attributes][0][latitude]" type="hidden" value="51.0504088">
</div>
</div>
EDIT2:
post.rb
class Post < ActiveRecord::Base
require "acts-as-taggable-on"
require "kaminari"
acts_as_taggable
self.table_name = "blog_posts"
self.paginates_per Blogit.configuration.posts_per_page
# ==============
# = Attributes =
# ==============
attr_accessible :title, :body, :tag_list, :blogger_id, :coverphoto, :locations_attributes
# ===============
# = Photo Model =
# ===============
has_attached_file :coverphoto,
:styles => {
:coverbar => "600x300>", :medium => "250x250^" , :thumb => "100x100^"},
#:source_file_options => {:all => '-rotate "-90>"'},
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:bucket => "backpackbug",
:path => "/:style/:id/:filename"
# ===============
# = Validations =
# ===============
validates :title, presence: true, length: { minimum: 6, maximum: 66 }
validates :body, presence: true, length: { minimum: 10 }
validates :blogger_id, presence: true
# =================
# = Associations =
# =================
belongs_to :blogger, :polymorphic => true
has_many :location_post
has_many :locations, :through => :location_post
belongs_to :profile
accepts_nested_attributes_for :locations, :allow_destroy => true, :reject_if => proc { |attributes| attributes['name'].blank? }
end end
This was solved with a combination of this and another answer, found here:
How can I fix this create function?
A short term fix is to add attr_accessible :_destroy and attr_accessor :_destroy.
Thanks both!
Add :_destroy to your attr_accessible list
attr_accessible ...., :_destroy
you should write to post.rb,
attr_accessible: locations_atributes
and
accepts_nested_attributes_for :locations, :allow_destroy => true
as you are updating the location object via post object.
replace f.hidden_field it must stay thus(line 2)
module ApplicationHelper
def link_to_remove_fields(name, f)
text_field_tag(:_destroy) + link_to_function(name, "remove_fields(this)")
end
I have three controllers - users, stories, categories. I want when I am logged in as a administrator to create categories and then to write stories for every category. I did part of the task but in DB in table Stories category_id is empty and I cannot understand how to fix it. Here is part of my code:
stories/new.html.erb:
<%= form_for(#story) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.collection_select :category_id, #categories, :id, :title %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Add" %>
</div>
<% end %>
stories_controller.rb:
class StoriesController < ApplicationController
before_filter :admin_user
def new
#story = Story.new
#categories = Category.all
#title = "Add news"
end
def create
#categories = Category.all
#story = current_user.stories.build(params[:story])
if #story.save
flash[:success] = "Successfullly added news"
redirect_to #story
else
#title = "Add news"
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
story.rb:
class Story < ActiveRecord::Base
attr_accessible :title, :content
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
default_scope :order => 'stories.created_at DESC'
end
category.rb:
class Category < ActiveRecord::Base
attr_accessible :title
has_many :stories
validates :title, :presence => true,
:length => { :within => 6..40 }
end
user.rb:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
has_many :stories
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
You need add attr_accessible :category_id to your story model
Its preventing mass assignment in your controllers create method. Alternatively you could pull out the category_id from your params hash and assign it on a separate line.