I'm attempting to validate and save an email from a form with three parameters: :name, :email, and :message, and then send the entire email. Currently, the email will send successfully without validating the parameters or creating an instance of Email.
Controller
def thank_you
#name = params[:name]
#email = params[:email]
#message = params[:message] || "Hello!"
if Email.create(name: #name, email: #email, message: #message)
ActionMailer::Base.mail(
:from => #email,
:to => 'erikvdw#comcast.net',
:subject => "A new contact form message from #{#name}",
:body => #message).deliver
end
end
Model
class Email < ActiveRecord::Base
validates_presence_of :name
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates_length_of :message, :maximum => 500, :minimum => 10
end
View
<%= form_tag("/thank_you") do %>
<div class="row">
<div class="col-md-5">
<div class="input-group">
<%= text_field_tag :name, nil, class: 'form-control', placeholder: 'Your Name' %>
</div>
</div>
<div class="col-md-7">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">#</span>
<%= text_field_tag :email, nil, class: 'form-control', placeholder: 'Your Email Address' %>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<div class="input-group text-area-wide">
<%= text_area_tag :message, nil, class: 'form-control text-area-wide', placeholder: 'When are you available?' %>
</div>
</div>
</div>
<br>
<%= submit_tag 'Get Started', class: 'btn btn-success' %>
<p>Skype required</p>
<% end %>
I think your problem in the operation
Email.create
because it's creating a instance in memory and don't save the instance to DB.
You must call save method or check validation method directly - email.valid?, like this:
email = Email.create(name: #name, email: #email, message: #message)
if email.valid?
#send email
end
Related
I'm working on a simple one-page contact form. Contact model have two attributes: phone and email. Email should be validated on backend (i did it in my model). But user can fill either email or phone in the contact form and send it. No Email field in necessary and i don't know how to make it optional.
contact.rb
class Contact < MailForm::Base
attribute :phone
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i,
presence: false
def headers
{
:subject => "My Contact Form",
:to => "email#admin.com",
:from => %("#{phone}" <#{email}>)
}
end
end
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
flash.now[:notice] = 'Ваша заявка принята!'
render :new
else
flash.now[:notice] = 'Введите корректный email.'
render :new
end
end
private
def contact_params
params.require(:contact).permit(:phone, :email)
end
end
new.html.erb
<%= simple_form_for #contact, html: {class: 'form-inline'} do |f| %>
<div class="form-group">
<div class="col-sm-6">
<%= f.input_field :email, class: "form-control", placeholder: "email", required: false %>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<%= f.input_field :phone, class: "form-control", placeholder: "+7 (095) 123-45-67" %>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<%= f.button :submit, 'Submit', :class=> "btn btn-success" %>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<% flash.each do |key, value| %>
<div class="alert alert-info" role="alert">
<div class="alert alert-<%= key %>"><%= value %></div>
</div>
<% end %>
</div>
</div>
<% end %>
I'd probably go about it this way:
class Contact < MailForm::Base
attribute :phone
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i,
presence: false, allow_blank: true
validate :at_least_a_contact
def headers
{
:subject => "My Contact Form",
:to => "email#admin.com",
:from => %("#{phone}" <#{email}>)
}
end
private
def at_least_a_contact
unless phone.present? || email.present?
errors.add(:contact, "You need at least a contact method")
end
end
end
Use allow_blank: true in your validation in your model.
http://guides.rubyonrails.org/active_record_validations.html#allow-blank
I am working with the mail_form gem. I have already created an specific controller for the contact form and everythink seems right but when I submit any form the view does´nt change from the create one to the create one but the url does. It shows the localhost3000/gmm/contacts(which has changed from localhost3000/gmm/contacts/new). I am worried about this issue; Moreover, the new view shows the e-mail in the name´s field as showed in the image:
"http://2.bp.blogspot.com/-Q4qUs1CHm-M/Voqc-VYiXII/AAAAAAAAAdE/nJMxgpTEu5s/s320/problem1.jpg"
Controller file:
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact=Contact.new(params[:contact])
#contact.request=request
if #contact.deliver
flash.now[:error]=nil
else
flash.now[:error]='Cannot send message.'
render :new
end
end
end
New view:
<body>
<section>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 text-center">
<h2 class="margin-top-0 wow fadeIn">Get in Touch</h2>
<hr class="primary">
<p>We love feedback. Fill out the form below and we'll get back to you as soon as possible.</p>
</div>
<div class="col-lg-10 col-lg-offset-1 text-center">
<%= form_for #contact do |f| %>
<div class="col-md-6 text-faded">
<%= f.label :name %>
<%= f.text_field :name, required: true, :class => "form-control", :placeholder => "Name"%>
</div>
<div class="col-md-6 text-faded">
<%= f.label :email %>
<%= f.email_field :name, required: true, :class => "form-control", :placeholder => "Email" %>
</div>
<div class="col-md-12 text-faded">
<%= f.label :message %>
<%= f.text_area :message, as: :text, :class => "form-control", :rows=>"9", :placeholder => "Your message here.."%>
</div>
<div class="hidden">
<%= f.label :nickname %><br>
<%= f.text_field :nickname, hint:"leave this field blank"%>
</div>
<div class="col-md-4 col-md-offset-4">
<%= f.submit "Send Message", :class=> "btn btn-primary btn-block btn-lg" %>
</div>
<%end%>
</div>
</div>
</div>
</section>
Model:
class Contact<MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :message, :validate => true
attribute :nickname,:captcha => true
def headers
{
:subject => "Contact Form",
:to => "kurtco_91#hotmail.com",
:to => "yomi.89gm#gmail.com",
:from => %("#{name}" <#email>)
}
end
end
Routes:
Rails.application.routes.draw do
resources :contacts, only: [:new,:create]
get 'gmm/home'
get 'gmm/about'
get 'gmm/services'
get 'gmm/contact'
get '/change_locale/:locale', to: 'settings#change_locale', as: :change_locale
I think it must be a problem with the post verb or my routing but I did rake: routes several times and no progress. Thanks a lot for your help. I really appreciate it
Answer to Email showing in name field is you are actually saving email into name field.
change email field from this:
<%= f.email_field :name, required: true, :class => "form-control", :placeholder => "Email" %>
to this:
<%= f.email_field :email, required: true, :class => "form-control", :placeholder => "Email" %>
Answer to URL issue is:
in your controller after according to my assessment you should save the contact if u need. if contact save successfully you should redirect to new_contact_path.
controller should look like this:
def create
#contact=Contact.new(params[:contact])
#contact.request=request
if #contact.deliver
flash.now[:error]=nil
else
flash.now[:error]='Cannot send message.'
redirect_to new_contact_path
end
end
I'm learning rails and building an authentication system using guides from around the web and following railscasts tutorials.
I've come to a stand still at the moment and need a bit of assistance if possible.
When ever I try to edit the user profile, I get an error message which tells me that it can't create an account due to fields such as email and username already being taken.
Looking around it seems it's related to how my edit form is being submitted, but I can't solve it!
Any help would be appreciated.
Users_controller.rb
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
edit.html.erb
<%= form_for :user, url: '/users' do |f| %>
<form class="m-t" role="form" action="#">
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control', autocomplete: "off" %>
</div>
<div class="form-group">
<%= f.label :user_type %>
<%= f.select(:user_type, ['Admin', 'Technical', 'Accounts'], {}, { :class => 'form-control' }) %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :telephone %>
<%= f.text_field :telephone, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :mobile %>
<%= f.text_field :mobile, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :user_name %>
<%= f.text_field :user_name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :company_admin%>
<%= f.check_box :company_admin, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :user_admin %>
<%= f.check_box :user_admin, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :emergency_contact %>
<%= f.check_box :emergency_contact, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.submit "Submit", class: "btn btn-primary block full-width m-b" %>
</div>
</form>
<% end %>
Rails Log
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'emailaddress#gmail.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."user_name" = 'AUserName' LIMIT 1
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :name, presence: { message: "Please enter your name." }
validates_uniqueness_of :email, presence: { message: "Please enter your email address." }
validates_format_of :email, with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z] {2,})\z/i, message: "Please enter a valid email address.", allow_blank: true
validates :telephone, presence: { message: "Please enter your phone number." }
validates :mobile, presence: { message: "Please enter your mobile number." }
validates_uniqueness_of :user_name, presence: { message: "Please enter your user name." }
validates_confirmation_of :password, presence: { message: "Please enter your password" }, allow_nil: true
before_create { generate_token(:auth_token) }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
end
Wait I'm wrong on the validation. Just spotted it.
<%= form_for :user, url: '/users' do |f| %>
This won't use the #user object, which means rails thinks you're trying to create a user.
Switch it to
<%= form_for #user do |f| %>
Rails will also infer the correct place to post to so you won't need the url option anymore.
I am saving an email to the database and then sending it. I am using the email model to validate the inputs, but I'm not sure how to display the error messages. I am getting an undefined method `errors' for nil:NilClass error for the fullmessage.errors.any? line in the index action(highlighted below)
View
<%= form_tag("/thank_you") do %>
<% if #fullmessage.errors.any? %> # <----- This line
<h3>Errors</h3>
<ul>
<% #fullmessage.errors.full_messages.each do |message| %> # Would also cause an error if exemption not already raised
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<div class="row">
<div class="col-md-5">
<div class="form-group">
<%= text_field_tag :first_name, nil, class: 'form-control', placeholder: 'First Name' %>
</div>
</div>
<div class="col-md-7">
<div class="form-group">
<%= text_field_tag :last_name, nil, class: 'form-control', placeholder: 'Last Name' %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<%= text_field_tag :email, nil, class: 'form-control', placeholder: 'Email Address' %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group text-area-wide">
<%= text_area_tag :message, nil, class: 'form-control text-area-wide', placeholder: 'When are you available?' %>
</div>
</div>
</div>
<%= submit_tag 'Get Started', class: 'btn btn-success' %>
<p>Skype required</p>
<% end %>
Controller
def thank_you
#first_name = params[:first_name]
#last_name = params[:last_name]
#email = params[:email]
#message = params[:message] || "Hello!"
#fullmessage = Email.create(first_name: #first_name, last_name: #last_name, email: #email, message: #message)
if #fullmessage.valid?
ActionMailer::Base.mail(
:from => #email,
:to => 'erikvdw#comcast.net',
:subject => "A new contact form message from #{#first_name} #{#last_name}",
:body => #message).deliver
else
redirect_to root_path
flash[:alert] = 'There was an issue with your submission'
end
end
Model
class Email < ActiveRecord::Base
validates_length_of :first_name, :maximum => 25, :minimum => 2
validates_length_of :first_name, :maximum => 30, :minimum => 2
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
validates_length_of :message, :maximum => 500, :minimum => 20
end
You have two options:
Use render instead of redirect to (this way you'll keep your #fullmessage object.
Save error into flash[:alert] and display it in the view
The 2nd option is more universal, you could add the relevant code to the layout and use it across the whole site. E.g.:
<% if !flash.empty? %>
<div id="flash">
<% flash.keys.each do |k| %>
<div class="alert alert-<%= k %>">
<%= flash[k] %>
</div>
<% end %>
</div>
<% end %>
Nil class means that the #fullmessage is nil and hasn't been set, and nil does not have the method errors, hence the error.
When you redirect, the #fullmessage value will have nothing because http is stateless. Absent caching and cookies, every variable is recreated with every request. think what you are trying to do is display the flash messages, if that is the case you can add the #fullmessage.errors to the flash and be able to display that on the redirect.
I am creating an application through which a user will be able to create an account. When they create an account, in the same form they will be able to create an organization that will then be tied to their user. Once that user has created their account (and an organization) other users will be able to create an account and use an "access code" to join that organization as well. Looking at the code may explain it better.
The reason i'm posting on SO is because i have a feeling there is a better / more efficient way to do it than what i am currently doing. I'm using nested_forms (maybe not correctly) and i don't think i'm doing the associations the right way because, for example, i haven't been able to get the edit form to fill out the organization fields.
I am using sorcery for the authentication as well.
users_controller.rb
def new
#user = User.new
end
def create
#user = User.new(user_params)
if params[:user][:organization][:name].blank?
flash.now[:error] = "You must specify an organization name."
render :new
else
if params[:user][:organization][:access_code].blank?
# create new organization
#access_code = "#{SecureRandom.urlsafe_base64(16)}#{Time.now.to_i}"
#organization = Organization.create(:name => params[:user][:organization][:name], :access_code => #access_code)
#user.organization_id = #organization.id
#user.is_admin = true
else
# try and add someone to an organization
#organization = Organization.find(:all, conditions: ["name = ? AND access_code = ?", params[:user][:organization][:name], params[:user][:organization][:access_code]])
if #organization.empty?
flash.now[:error] = "No organization has been found with that name and access code."
render :new
return
else
#user.organization_id = #organization.first.id
end
end
if #user.save
user = login(#user.email, params[:user][:password])
if user
flash[:success] = "Your account has been successfully created!"
redirect_to admin_dashboard_path
end
else
flash.now[:error] = "Something went wrong! Please try again."
render :new
end
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.is_admin?
if params[:user][:organization][:name].blank? && params[:user][:organization][:name] != #user.organization.name
params[:user][:organization][:name] = #user.organization.name
end
if params[:user][:organization][:access_code].blank? && params[:user][:organization][:access_code] != #user.organization.access_code
params[:user][:organization][:access_code] = #user.organization.access_code
end
#organization = Organization.find(params[:user][:organization_id])
#organization.name = params[:user][:organization][:name]
#organization.access_code = params[:user][:organization][:access_code]
#organization.save
end
if #user.update(user_params)
flash[:success] = "Your settings have been updated!"
redirect_to edit_admin_user_path(#user.id)
else
flash.now[:error] = "Something went wrong! Please try again."
render :edit
end
end
private
def user_params
params.require(:user).permit(:organization_id, :email, :password, :password_confirmation, :full_name, :remember_me, {:organization_attributes => [:name, :website, :description, :access_code]})
end
users.rb
class User < ActiveRecord::Base
authenticates_with_sorcery!
belongs_to :organization
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates_presence_of :full_name
validates_presence_of :email
validates_uniqueness_of :email, :on => :create
validates_format_of :email, :with => VALID_EMAIL_REGEX, :on => :create
validates_presence_of :password, :on => :create
validates_confirmation_of :password
end
organization.rb
class Organization < ActiveRecord::Base
authenticates_with_sorcery!
has_many :users, :dependent => :destroy
accepts_nested_attributes_for :users
validates_presence_of :name
end
new.html.erb
<% provide(:title, 'Create a User') %>
<h1>Create a User</h1>
<p>Use the form below to create an account.</p>
<%= nested_form_for([:admin, #user], html: {role: "form"}) do |f| %>
<%= render "shared/error_messages", obj: #user %>
<fieldset>
<legend>User Information</legend>
<div class="form-group">
<%= f.label :full_name, "Full Name" %>
<span class="help-block">How should others see you?</span>
<%= f.text_field :full_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %>
<span class="help-block">Your email address is used as your login.</span>
<%= f.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
</fieldset>
<%= f.fields_for :organization do |o| %>
<fieldset>
<legend>Associated Organization</legend>
<div class="form-group">
<%= o.label :name, "Organization Name" %>
<span class="help-block">This is the name of the organization you are a part of.</span>
<%= o.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= o.label :access_code, "Organization Access Code" %>
<span class="help-block">Leaving this field blank will setup a new organization.</span>
<%= o.text_field :access_code, class: "form-control" %>
</div>
</fieldset>
<% end %>
<div class="form-actions">
<%= f.submit "Create Account", class: "btn btn-primary" %>
<%= link_to "Cancel", :back, class: "text-btn" %>
</div>
<% end %>
edit.html.erb
<% provide(:title, "Edit User: #{#user.full_name} (#{#user.organization.name})") %>
<h1>Edit User: <%= #user.full_name %> (<%= #user.organization.name %>)</h1>
<p>Use the form below to manage your account.</p>
<%= nested_form_for([:admin, #user], html: {role: "form"}) do |f| %>
<%= render "shared/error_messages", obj: #user %>
<fieldset>
<legend>User Information</legend>
<div class="form-group">
<%= f.label :full_name, "Full Name" %>
<span class="help-block">How should others see you?</span>
<%= f.text_field :full_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :email %>
<span class="help-block">Your email address is used as your login.</span>
<%= f.text_field :email, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, placeholder: "leave blank to keep password unchanged", class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: "form-control" %>
</div>
</fieldset>
<% if #user.is_admin? %>
<%= f.fields_for :organization do |o| %>
<fieldset>
<legend>Associated Organization</legend>
<div class="form-group">
<%= o.label :name, "Organization Name" %>
<span class="help-block">This is the name of the organization you are a part of.</span>
<%= o.text_field :name, class: "form-control", value: #user.organization.name %>
</div>
<div class="form-group">
<%= o.label :access_code, "Organization Access Code" %>
<span class="help-block">Leaving this field blank will setup a new organization.</span>
<%= o.text_field :access_code, class: "form-control", value: #user.organization.access_code %>
</div>
</fieldset>
<% end %>
<%= f.hidden_field :organization_id %>
<% end %>
<div class="form-actions">
<%= f.submit "Update User", class: "btn btn-primary" %>
<%= link_to "Cancel", :back, class: "text-btn" %>
</div>
<% end %>
Ok, those are all the files making it happen. Now, i have the application doing almost everything i need it to do but this doesn't feel like production-level code to me.
One issue i know i am having is that if a user types something in the organization field and nothing else the controller will create and save the organization and then render the form back with the user validation errors. I don't want it to save the organization if there are validation errors in the user model.
I'm really just asking for advice if there is a better way of doing what i am trying to do. If you can't tell exactly what i'm trying to do with this code or have any questions please let me know!
Take a look at this post: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Of particular interest will be the section on "3. Extract Form Objects".