This is a pretty basic question, but I'm having difficulty incorporating it in to my application. I've looked at other similar questions on SO, but they all are using the contact page as a separate page.
I have a front-end of a Rails app that is just a small public facing site using stellar.js for parallax scrolling.
At the last part of the page, I would like to have a "Contact Us" form, but I'm getting a
NoMethodError in Welcome#index undefined method `model_name' for NilClass:Class
Here are the related files:
routes.rb
TestApp::Application.routes.draw do
get "welcome/index"
root :to => 'welcome#index'
match 'contact' => 'contact#new', :as => 'contact', :via => :get
match 'contact' => 'contact#create', :as => 'contact', :via => :post
app/views/welcome/index.html.erb
<%= render "contact" %>
The partial for the contact section of the page app/views/welcome/_contact.html.erb
<%= form_for #message, :url => contact_path do |form| %>
<fieldset class="fields">
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.text_field :email %>
</div>
<div class="field">
<%= form.label :subject %>
<%= form.text_field :subject %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
</fieldset>
<fieldset class="actions">
<%= form.submit "Send" %>
</fieldset>
<% end %>
app/controllers/contact_controller.rb
class ContactController < ApplicationController
def new
#message = Message.new
end
def create
#message = Message.new(params[:message])
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(root_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :new
end
end
end
message.rb
class Message
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :subject, :body
validates :name, :email, :subject, :body, :presence => true
validates :email, :format => { :with => %r{.+#.+\..+} }, :allow_blank => true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
The question is what do I need to do to make this form to function correctly in the welcome#index view?
You need to have #message = Message.new defined in every action that needs #message to be present.
So that means you need this in WelcomeController:
def index
#message = Message.new
end
A shortcut is to just add it to the top of the partial in case it's not set:
<% #message ||= Message.new %>
(But you need to decide if mixing in calls to the model within your views is your style. Some devs don't have a problem with this, and some do.)
You can change following things:
In routes:
Remove:
match 'contact' => 'contact#new', :as => 'contact', :via => :get
match 'contact' => 'contact#create', :as => 'contact', :via => :post
Add:
resources :contact # It will add 7 default REST routes and standard practice model name should be plural if you created your model with singular then keep it singular
In _contact.html.erb partial form path needs to be new_contact_path
<%= form_for Message.new, :url => contact_path do |form| %>
class Message should inherit ActiveRecord::Base
class Message < ActiveRecord::Base
end
In create action else part should be:
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(root_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :template => "welcome/index"
end
Related
I am new to rails. I have created an app and a simple contact form. When I fill the contact form out it seems to submit everything fine. I don't get any errors, and the console shows that it worked.
However I am not receiving these emails in my inbox or spam folder. Can anyone tell me what I am doing wrong?
I followed this tutorial
Routes
match '/contacts', to: 'contacts#new', via: 'get'
resources "contacts", only: [:new, :create]
Contacts Controller
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
redirect_to root_path
flash.now[:notice] = 'Thank you for your message. We will contact you soon!'
else
flash.now[:error] = 'Cannot send message.'
render :new
end
end
end
Model
class Contact < MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :message
attribute :nickname, :captcha => true
# Declare the e-mail headers. It accepts anything the mail method
# in ActionMailer accepts.
def headers
{
:subject => "My Contact Form",
:to => "myemail#gmail.com",
:from => %("#{name}" <#{email}>)
}
end
end
New.html.erb
<div align="center">
<h3>Send A message to Us</h3>
<%= simple_form_for #contact, :html => {:class => 'form-horizontal' } do |f| %>
<%= f.input :name, :required => true %>
<%= f.input :email, :required => true %>
<%= f.input :message, :as => :text, :required => true %>
<div class= "hidden">
<%= f.input :nickname, :hint => 'Leave this field blank!' %>
</div>
<div>
</br>
<%= f.button :submit, 'Send message', :class=> "btn btn-primary" %>
</div>
<% end %>
</div>
Create.html.erb
<div>
<% flash.each do |key, value| %>
<div>
×
<%= value %>
</div>
<% end %>
</div>
Using the Mail_form Gem in rails, I can verify that my mail configuration is correct; however I don't receive any errors in my logs.
contact.rb [app/models/contact.rb]
class Contact < MailForm::Base
include MailForm::Delivery
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :message
attribute :nickname, :captcha => false
# Declare the e-mail headers. It accepts anything the mail method
# in ActionMailer accepts.
def headers
{
:subject => "IT Site Contact",
:to => "kompinski#gmail.com",
:from => %("#{name}" <#{email}>)
}
end
end
contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new(params[:contact])
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
#contact.deliver
end
end
routes.rb
resources :contacts, only: [:new, :create]
get 'contact' => 'contacts#new'
post 'contact' => 'contacts#create'
new.html.erb [/views/contacts/new.html.erb]
<div class="container">
<div class="col-md-6"><h2>Contact us</h2>
<hr />
<form role="form">
<%= twitter_bootstrap_form_for #contact, url: new_contact_path, method: :post do |f| %>
<div class="medium">
</div>
<div class="medium">
<%= f.text_field :name, :required => true %>
</div>
<div class="medium">
<%= f.email_field :email, :required => false %>
</div>
<div class="medium">
<%= f.text_area :message, :as => :text, :required => true %>
</div>
<div class="btn">
<%= f.submit 'Submit' %>
<% end %>
</div>
</form>
</div>
</div>
** Edit **
Also I can send it directly from the form by using Contact.new(params[:contact]).deliver, but only when resubmit the address; however when I load the page containing the form it indicates 'undefined method `model_name' for TrueClass:Class'
This code worked for my controller where the issue seemed to be:
def new
#contact = Contact.new
if
Contact.new(params[:contact]).deliver
redirect_to '/contacts/thanks', :alert => ["Yeah!"]
end
I have a User model and a Company model linked like this:
class User < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company
end
class Company < ActiveRecord::Base
has_many :users
end
On the sign in page, I want the user to set up both his info (mail, password) and his company info (several fields). So my form looks like this:
<%= simple_form_for #user, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.input :email, :required => true, :placeholder => "user#domain.com" %>
<%= f.input :password, :required => true %>
<%= f.input :password_confirmation, :required => true %>
<h2>Company info</h2>
<%= simple_fields_for :company, :html => { :class => 'form-horizontal' } do |fa| %>
<%= fa.input :name %>
<%= fa.input :url %>
<%= fa.input :description, :as => :text, :input_html => { :cols => 60, :rows => 3 } %>
<%= fa.input :logo %>
<%= fa.input :industry %>
<%= fa.input :headquarters %>
<% end %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
root_url, :class => 'btn' %>
</div>
<% end %>
My user model has a company_id:integer field. So logically, when I sign in the user, the first thing to do is to create the Company before the User and then give to the user creation model the appropriate company_id. So I wrote this:
class UsersController < ApplicationController
before_create :create_company
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Registration successful."
else
render :action => 'new'
end
end
private
def create_company
#company = Company.new(params[:company])
if #company.save
self.company_id = #company.id
else
render :action => 'new'
end
end
end
Problem is: when accessing /users/new I get this error:
undefined method `before_create' for UsersController:Class
What's going wrong? I checked, before_create has not been deprecated, I'm in Rails 3.2.8. This is probably something stupid with my create_company method but I can't figure why...
Thanks a lot for helping!
before_create is a hook method belonging to ActiveRecord
before_filter is a hook method belonging to Controller.
so I suggest you to re-build your code after you make clear which is which. ^_^
I have been having some serious trouble all weekend trying to get this basic contact form to work correctly.
Effectively I want the user to be able to complete the form, hit send and have the message send straight to a predefined email address.
The error I am continually getting is:
NoMethodError in Messages#new
Showing C:/Sites/jobapp_v2/app/views/messages/new.html.erb where line #1 raised:
undefined method `[]' for nil:NilClass
Extracted source (around line #1):
1: <%= form_for #message, :url => contact_path do |f| %>
2:
3: <div class="field">
4: <%= f.label :name %>
I have the following setup:
Messages controller
class MessagesController < ApplicationController
def new
#user = current_user
#message = Message.new
end
def create
#message = Message.new(params[:message])
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(root_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :new
end
end
end
Message Model
class Message < ActiveRecord::Base
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :subject, :body
validates :name, :email, :subject, :body, :presence => true
validates :email, :format => { :with => %r{.+#.+\..+} }, :allow_blank => true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
Routes.rb
JobappV2::Application.routes.draw do
devise_for :users
resources :newsletters
match "contact" => "messages#new", :as => "contact", :via => :get
match "contact" => "messages#create", :as => "contact", :via => :post
get "pages/about"
get "pages/contact"
get "pages/terms"
resources :jobs
resources :users do
resources :jobs
end
root :to => 'jobs#index'
end
NotificationsMailer.rb
class NotificationsMailer < ActionMailer::Base
default :from => "advertise#artisanmag.co.uk"
default :to => "tom.pinchen#artisanmag.co.uk"
def new_message(message)
#message = message
mail(:subject => "Hello")
end
end
Views/notification_mailer/new_message.text.erb
Name: <%= #message.name %>
Email: <%= #message.email %>
Subject: <%= #message.subject %>
Body: <%= #message.body %>
Views/messages/new.html.erb
<%= form_for #message, :url => contact_path do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :subject %>
<%= f.text_field :subject %>
</div>
<div class="field">
<%= f.label :body %>
<%= f.text_area :body %>
</div>
<%= f.submit "Send" %>
<% end %>
I really for can't work out at all what is causing this undefined method error so any help people can offer would really be much appreciated! Thanks in Advance :)
The way you have hooked things up, you don't need :url => contact_path
<%= form_for #message do |f| %>
will work just fine.
Ok so I am having a problem with doing multiple forms in rails. here is the code below
Models
class Profile < ActiveRecord::Base
belongs_to :user
has_attached_file :avatar, :styles => { :medium => "134x137>", :thumb => "111x111>", :tiny => "32x38>" }
validates_attachment_content_type :avatar, :content_type => ['image/pjpeg','image/jpeg', 'image/x-png', 'image/png', 'image/gif']
class User < ActiveRecord::Base
has_one :profile, :dependent => :destroy
Profile Controller
def edit
#user = User.find(params[:id])
#profile = #user.profile
end
Profiles Edit View
<% form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<input id="send_update" name="send" type="submit" value="Update" />
<% end %>
<% form_for #profile , :html => { :multipart => true } do |f| %>
<%= render :partial => 'form', :locals => {:f => f, :profile => #profile, :title => 'Edit Profile'} %>
<%= submit_tag 'Update', :style => 'text_align:right'%>
<% end %>
Profile _form partial
<label>Upload Avatar</label>
<tr><%= f.file_field :avatar %></tr>
So basically I have two forms in the edit view and when i click on the second Update to update the avatar I go to the users update and i get this flash error "Sorry, something went wrong"
def update
#user = User.find(params[:id])
current_email = #user.email
if #user.update_attributes(params[:user])
UserMailer.deliver_email_changed (#user) if email_changed?(current_email, #user.email)
flash[:notice] = "<h1>Account updated!</h1>"
redirect_to edit_user_path(#user)
else
flash.now[:error] = "Sorry, something went wrong"
render :action => :edit
end
end
My questions are this
Is there a better way to structure this so maybe i have one form?
Why is it not saving now and whats causing the issue?
The method you are using to update is wrong, it is syntactically invalid (you're missing an end). It should be:
def update
#user = User.find(params[:id])
current_email = #user.email
if #user.update_attributes(params[:user])
UserMailer.deliver_email_changed (#user) if email_changed?(current_email, #user.email)
flash[:notice] = "<h1>Account updated!</h1>"
redirect_to edit_user_path(#user)
else
flash.now[:error] = "Sorry, something went wrong"
render :action => :edit
end
end
It should be two forms indeed, as I'm guessing you don't want any of the values of one form to submit if the user performs the other action.
Now, organize your controllers. You are calling #user = User.find(params[:id]) on your ProfilesController, but the id you're passing is an user's one. Either this should be on the user's controller, and update the associated profile from there, or you should receive the id of the profile object instead.
I'd go with the first one. You can update the Profile object of a user using accepts_nested_attributes_for, and your forms would be like:
<% form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.submit, :id => ... %>
<% end %>
<% form_for #user, :html => { :multipart => true } do |f| %>
<% f.fields_for :profile do |profile_form| %>
<%= render :partial => 'form', :locals => {:f => profile_form, :title => 'Edit Profile'} %>
<%= submit_tag 'Update', :style => 'text_align:right'%>
<% end %>
<% end %
If the error is that the password cannot be blank, may be due to a validates_presence_of :password, :password_confirmation. You should use a conditional validation there
Troubleshooting would help:
Remove the if/else and keep the #user.update_attributes(params[:user]). Rails would give you a more detailed error message.
Check the form structure (html source) especially for field naming.
Check the log files for DB statements
HTH