class Person < ActiveRecord::Base
before_save {self.email = email.downcase}
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { maximum: 6}
end
I am really new to Ruby. I was learning from Michael Hartl's tutorial. When creating signup form (tutorial 7) I got stuck in displaying error messages ( like if we leave any field blank there should be notifications in red right?).I added error_messages.html.erb file. Rendered it in form. Still there are no messages.
What I guessed is, I am using :user in my form creation to save the user. where as it should be #user. So that it can create user?
but when I did so, It gave me anonymous error of user_path. I searched for that display of error messages on stack but was not able to find.
Kindly help me with it. I am stuck since very long.
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(:person) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
<% if #person.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
the form contains <%= #person.errors.count %> errors.
</div>
<ul>
<%= #person.errors.full_messages.each do |msg| %>
<li> <%= msg %> </li>
<% end %>
</ul>
</div>
<% end %>
class PersonsController < ApplicationController
def show
#person = Person.find(params[:id])
end
def new
#person = Person.new
end
def create
#person = Person.new(user_params)
if #person.save
else
render new
end
end
private
def user_params
params.require(:person).permit(:name, :email, :password, :password_confirmation)
end
end
Rails.application.routes.draw do
get 'persons/show'
root 'staticpages#home'
get 'help' => 'staticpages#help'
get 'about' => 'staticpages#about'
get 'signUp' => 'persons#new'
resource :person
resources :persons
end
// error when i use #user in form. Instead of :user
NoMethodError in PersonsController#new
undefined method `users_path' for #<#<Class:0x007fdb68c0ee78>:0x007fdb68c0e428>
Extracted source (around line #220):
if options.empty?
recipient.send(method, *args)
else
recipient.send(method, *args, options)
end
Based on the code I have seen in the GitHub repo, the major problem I identified was with the naming. There was a large level of conflict in the name person in that its plural is people and not persons.
Rails has its way of pluralizing model names so User has a UsersController and Person has PeopleController and so forth.
Following are the changes required to fix the problems with sign up:
You need to change your controller name from PersonsController to PeopleController (both class name and file name).
In the PeopleController, the strong parameters method Person_params needs to change to lowercase (person_params). Otherwise, Rails would treat it as a constant name and start hunting for it and wouldn't find it.
You'll have to update the persons folder name in the app/views folder to people for the same reason specified above.
In your routes.rb file, there are two changes required. Change resource :person to resources :people and get 'signUp' should match to 'people#new' instead of 'persons#new' (now you know why).
Create a new file in app/views/people called create.html.erb. Once a person is created, Rails automatically renders this file and will throw an exception if it does not find it.
In the file app/views/people/new.html.erb, change the variable passed to form_for from :person to #person. #person is an instance variable initialized when that page is visited (see the new action in the PeopleController).
I'm not sure if this change will be needed, but if you face any errors after making the above changes, add gem 'therubyracer' to your Gemfile and run bundle install. This will install the rubyracer gem which I believe will be required for this version of Rails.
You should really familiarize yourself with the fundamentals of the framework and the Ruby language. It'll help you identify and debug these issues yourself. But I figured since you're new to it, this lengthy answer might help get rid of your frustration :).
You have used the User model in multiple places. The actual model is called Person. Switch to this model name in all the controllers and the model class.
And I'd also like to make a suggestion. When studying the tutorial, please do not blindly copy and paste snippets. Understand what their purpose is and write them in your files on your own.
Related
I already know there is a lot of undefined method questions, But I can't see whats wrong with mine so I need some help!
heres my form that i have
<% title("Home Page") %>
<h1><i class="fa fa-home"></i> Add Event <small>views/pages/home.html.erb</small></h1>
<div class="row">
<%= simple_form_for Newevent.new do |f| %>
<%= f.input :eventname, required: true %>
<%= f.input :eventdesc %>
<%= f.input :eventdate %>
<%= f.input :eventimage %>
<div class="col s6">
<%= f.input :stubhublink %>
<%= f.input :seatwavelink %>
<%= f.input :viagogolink %>
</div>
<%= f.button :submit %>
<% end %>
</div>
I also have this in the controller
def create
create_params = params[:newevent].permit(:eventname, :eventdesc, :eventdate, :eventimage, :viagogolink, :seatwavelink, :stubhublink)
#newevent = Newevent.new(create_params)
byebug
#newevent.save!
end
and this in the model
class Newevent < ActiveRecord::Base
def params
params.require(:newevent).permit(:eventname, :eventdesc, :eventdate, :eventimage, :viagogolink, :seatwavelink, :stubhublink )
end
end
It was working fine with 3 (which were eventname, eventdate and eventimage) however after adding the other 4 in it now doesn't work. Any ideas?
Sorry heres the error!
NoMethodError in Newevents#new
Showing /Users/samroberts/Desktop/admitme/app/views/newevents/new.html.erb where line #6 raised:
undefined method `eventdesc` for #<Newevent:0x007fcaeee41f68>
Sam
Several problems here buddy:
1. eventdesc Missing
The simple explanation for your error is that your eventdesc attribute is missing from your NewEvent model's table.
Since we don't have your table - or migrations - to observe, I'll have to give you a simple test:
<%= simple_form_for Newevent.new do |f| %>
<%= f.input :eventname, required: true %>
<%= f.input :eventdesc %> #-> remove this line
...
Remove that, refresh the page and see if it works. If the error persists, it may mean another attribute is missing. If it disappears, it means this attribute is missing from your db, and as such you should use rails g migration to create a new one:
$ rails g migration AddEventDesc
#db/migrate/add_event_desc_xxxxxxxx.rb
class AddEventDesc
def change
add_column :new_events, :eventdesc, :string
end
end
2. Params
Part of Rails 4's infrastructure is to use strong params to pass data from your controller to model.
As such, you need the following syntax:
#app/controllers/new_events_controller.rb
class NewEventsController < ApplicationController
def new
#newevent = NewEvent.new
end
def create
#newevent = NewEvent.new new_event_params
#newevent.save
end
private
def new_event_params #-> you can call this whatever you like
params.require(:newevent).permit(:eventname, :eventdesc, :eventdate, :eventimage, :viagogolink, :seatwavelink, :stubhublink )
end
end
You need to keep your strong params function in your controller, not your model.
3. Model Name
Finally, this won't do much for you directly, but in the long run will help you massively; your model name.
Your model is NewEvent.
If this is what you want to call it, that is good. However, I have found the best way forward with model names is to keep them simple, preferably to one word.
I'd strongly recommend calling your model Event, so you can call #event = Event.new etc -- it just flows better.
I'm learning Rails by following Hartl's tutorial and making my own adjustments to it. Now, I would like to extent it and add a contact form that sends an email message. Such is not included in the tutorial, but by the end of chapter 10 we're learned to use the mailer method and we've configured SendGrid on Heroku.
I already have the view set up in the routes and think it would require the following additional steps:
1) Terminal. rails generate mailer ContactForm
2) In app/mailers/contactform.rb:
def send_contactform_email(visitor)
#visitor = visitor
mail( :to => myemail#example.com, :from => visitor.email, :subject => 'Contact form' )
end
3) app/views/contactform_mailer/ (the view for the mail message) for example:
<h1>Website contact form</h1>
<p>On <$= ... %> <%= "#{#visitor.name} (#{#visitor.email} sent the following message:" %></p>
<p><%= #visitor.message %></p>
4) app\controllers\static_pages_controller (or another location?)
# Sends contact form email.
def send_contact_form_email
ContactFormMailer.send_contactform_email(visitor).deliver_now
redirect_to contact_path, notice: 'Message sent'
end
5) app\views\static_pages\contact.html.erb (I'm not sure about the first line, should I also do something in the routes.rb? My guess is this first line will have to tell to execute the method in step 4, which is not going to work the way it is now.)
<%= form_for(:static_pages, url: contactform_path) do |f| %>
<i class="pt-row-icon glyphicon glyphicon-user"></i> <%= f.label :name %>
<%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :email %>
<%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<i class="pt-row-icon glyphicon glyphicon-envelope"></i> <%= f.label :message %>
<%= f.text_area :message, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
I don't think this is 100% correct yet, particularly the bold sections. What are your thoughts?
UPDATE, VERSION 2: I've tried to make the updates as suggested by Ven and now have the code below. The idea as I understand it is that
the controller in def contact sets the #message variable.
the form_for knows it should fill this variable with params[:message].
the controller adopts the values from the form_for and passes them to the mailer.
the mailer uses the mailer view to design the message to be sent.
the mailer sends it back to the controller that send the message.
1) App/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
before_action :valid_email?, only: [:send_message_email]
# Shows the contact form page
def contact
#message = message(message_params)
end
# Sends the message.
def send_message_email
#message = message(message_params)
if #message.valid?
MessageMailer.new_message(#message).deliver_now
redirect_to contact_path, notice: "Your messages has been sent."
else
flash[:alert] = "An error occurred while delivering this message."
render :new
end
end
private
def message_params
params.require(:message).require(:name, :email, :content)
end
def valid_email?(email)
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
email.present? && (email =~ VALID_EMAIL_REGEX)
end
end
2) Contact form in app\views\static_pages\contact.html.erb:
<%= form_for(message: params[:message], url: contact_path) do |f| %>
<%= f.label :name %> <%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>
<%= f.label :email %> <%= f.email_field :email, placeholder: 'Email', class: 'form-control' %>
<%= f.label :content %> <%= f.text_area :content, placeholder: 'Your message…', class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary" %>
<% end %>
3) Routes.rb
get 'contact' => 'static_pages#contact', as: 'contact'
post 'contact' => 'static_pages#send_message_email'
4) App/views/message_mailer.text.erb (and html.erb)
<%= #message[:name] %> <%= #message[:email] %> wrote:
<%= #message[:content] %>
5) App/mailers/message_mailer.rb
class MessageMailer < ApplicationMailer
default to: "myemail#example.com>"
def new_message(message)
#message = message
mail to: "myemail#example.com"
mail from: #message[:email]
mail subject: "Message from #{message[:name]}"
end
end
Now when I try to visit the contact form on the server, I get the error message: param is missing or the value is empty: message. It refers to the params.require(:message).require(:name, :email, :content) line. Not sure what I'm doing wrong. Changing it to params.require(:message).permit(:name, :email, :content) makes no difference.
4) app\controllers\static_pages_controller (or another location?)
This seems to be correct, if this is the github repo for said app.
def send_contact_form_email
You controller has an issue: this action will try to send the email, not matter if it's used in POST or GET. You should use two different actions, one for displaying the view (using GET), and one for sending the email (using the mailer class you created). (at this point, you might want to create another controller)
ContactFormMailer.send_contactform_email(visitor).deliver_now
Then, moving on: what you pass to your mailer is "visitor". There's no such variable.
You probably want to access something out of the params hash (which contains parameters for GET and POST requests), and use the same key as your form (form_for(:visitor ... => params[:visitor] (so you want to change that :static_pages)).
<p>On <$= ... %> <%= "#{#visitor.name} (#{#visitor.email} sent the following message:" %></p>
As this returns an object, and not a hash, #visitor.email needs to be #visitor[:email] inside the mailer.
One last thing: simply using params[:visitor] will mean people could leave the field blanks. You might want to look into strong parameters, that were added in Rails 4 (the book seems somewhat outdated?).
And lastly, you need to add routes to be able to reach these actions (one for the GET request - display the view - and one for the POST request - to submit the form).
PS:
mail( :to => myemail#example.com, :from => visitor.email, :subject => 'Contact form' )
Warning: here, you forgot to quote the email address. Also, you swapped the to/from parameters. You want to send TO your visitor email, not from it.
EDIT
params.require(:message).require(:name, :email, :content)
This will require said keys, but AFAIK on the same "level" as :message - the top one. You want to use permit:
params.require(:message) # require "namespace"
.permit(:name, :email, :content) # permit keys
#message = message(message_params)
Where is the message function defined?
mail to: "myemail#example.com"
mail from: #message[:email]
mail subject: "Message from #{message[:name]}"
This sends 3 different emails, since you called the mail function 3 times.
I am very new to Rails and I am facing a somehow weird problem, and my googling didn't helped me so far...
I have implemented a classical CRUD ressource following the Getting Started with Rails guide and I am blocking on the "update" part:
http://guides.rubyonrails.org/getting_started.html#updating-articles
This is part of my model "Devwork":
class Devwork < ActiveRecord::Base
validates :short_title, presence: true, uniqueness: true
validates :title_fr, presence: true, allow_blank: false
translates :title, :summary, :description
globalize_accessors
end
I am using the Globalize gem to persist localized data, and Globalize-accessor for the helpers.
Here is the controller's update action:
class DevworksController < ApplicationController
def update
#devwork = Devwork.find(params[:id])
if #devwork.update(devwork_params)
redirect_to #devwork
else
render :edit
end
end
private
def devwork_params
params.require(:devwork)
.permit!
end
end
And part of the form:
<%= form_for #devwork do |f| %>
<p>
<%= f.label :short_title %>
<%= f.text_field :short_title %>
</p>
<p>
<%= f.label :title_fr %>
<%= f.text_field :title_fr %>
<%= f.label :title_en %>
<%= f.text_field :title_en %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
short_title and title_fr are mandatory, while there exist another field title_en which is not. I want the update form to be shown again if the update fails (typically because of empty title_fr).
But it doesn't work. The update never fails (never entering render :edit) even if title_fr is empty. In fact, the update does nothing if one of the field is empty, it only updates non-empty fields.
I surely missed something somewhere, but I can't figure it out... perhaps a missuses of Globalize ?
Thanks for your help !
I am experimenting with a simple people/new page to practice showing error messages. Right now, with the below set-up, the error messages display okay but look a little awkward because the text says "Firstname can't be blank", "Lastname can't be blank" and so forth. Basically I want the text to say "First Name can't be blank" and "Last Name can't be blank" (with spaces), but I'm assuming the error messages are just following the attribute names I defined in the Model, and there's really no way to change those explicitly.
So how can I change that? Can I not achieve that change without making changes to this particular partial? (shared_error_messages)
Thanks,
Screenshot of the new view below.
people_controller.rb
class PeopleController < ApplicationController
def new
#person = Person.new
#people = Person.all
end
def create
#person = Person.new(person_params)
if #person.save
redirect_to new_person_path
else
render 'new'
end
end
private
def person_params
params.require(:person).permit(:firstname, :lastname, :age)
end
end
person.rb
class Person < ActiveRecord::Base
validates :firstname, presence: true, length: {maximum: 15}, format: { with: /\A[a-zA-Z]+\z/,
message: "only allows letters" }
validates :lastname, presence: true, length: {maximum: 15}, format: { with: /\A[a-zA-Z]+\z/,
message: "only allows letters" }
validates :age, presence: true, length: {maximum: 3}
end
new.html.erb
Enter your information
<hr>
<%= form_for #person do |f| %>
<%= render 'shared/error_messages', object: f.object %>
First Name: <%= f.text_field :firstname %><br>
Last Name: <%= f.text_field :lastname %><br>
Age: <%= f.number_field :age %><br>
<%= f.submit "See Your Life Clock" %>
<% end %>
shared/_error_messages
<% if object.errors.any? %>
<div id="error_explain">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this from being saved to DB</h2>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Assuming you're using Rails 3.2 or later, the "best" way to do this is with localization. Edit your en.yml file and add this:
en:
activerecord:
attributes:
person:
firstname: "First Name"
lastname: "Last Name"
The error reporting system will look up human-friendly names for your attributes from the localization file. Thie may seem heavy-handed, but in my opinion it is the best way because these names will be accessible anywhere, centralized, and easy to maintain.
If you need the friendly name in your own code, (for example, in a label on an edit form or a column header in a list table) you can access it like this:
Person.human_attribute_name(:firstname)
Now if you change the en.yml, the change will reflect throughout your site. And should you ever need to localize to another language, you're on the right track already.
If this is too much for you, you can change your validations to have complete sentences for their messages, and then change your _error_messages partial to look like this:
<% if object.errors.any? %>
<div id="error_explain">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this from being saved to DB</h2>
<ul>
<% object.errors.each do |attr, msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
An old question, but may be someone facing the same problem benefit from it, so I'm answering it.
In the view you used something like First Name: <%= f.text_field :firstname %> better to use something as follows which will give you good field names by default in your situation.
<%= f.label :firstname, 'First Name' %><br>
<%= f.text_field :firstname %>
Hi have simple rails site with no models, its used just for serving static pages.
The site has a Pages controller, but this is only serving up one home page made of partials.
Like such in the app/views/pages/home.html.erb
<%= render 'layouts/about' %>
<%= render 'layouts/services' %>
<%= render 'layouts/rooms' %>
<%= render 'layouts/breakfast' %>
<%= render 'layouts/guestbook' %>
<%= render 'layouts/contact' %>
The home page uses some html5/javascript which autoscrolls the page. So each section is prefaced with # to allow auto scrolling to that section.
<li><a class="home" href="#home">Home</a></li>
<li><a class="services" href="#services">Tarrifs</a></li>
<li><a class="portofolio" href="#portofolio">Rooms</a></li>
<li><a class="breakfast" href="#breakfast">Breakfast</a></li>
<li><a class="contact" href="#contact" >Contact </a></li>
<li><a class="services" href="#services">Blog / Whats On.</a></li>
<li><a class="guestbook" href="#guestbook">Guest Book</a></li>
<li class="description">Take a look.</li>
This all works fine.
Dev site is here
Now my question / issue is : I'd like to add a rails type ContactUS page.
Following various tutorials :
Simple Contact Us
Rails 3 Contact us
They all point to having a message model,ActionMailer, and contact controller, which works if you want to have a separate contact controller.
I'm stuck at trying to figure how I can build a contactUs form but keep it the pages controller to allow the autoscrolling to work as using a contact controller seems to change all the URL routes. I know this probably isn't the Rails way, but any help would be great.
Hope that made sense. Any ideas ?
I would do following:
Add a new model called "Form", app/models/form.rb
class Form
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :message
validates :name, presence: true
validates :email, presence: true, email: true
validates :message, presence: true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
modify your pages_controller:
def new
#form = Form.new
end
def create
#form = Form.new(params[:form])
if #form.valid?
redirect_to root_path, notice: "Thanks!")
else
render "new"
end
end
Add the form html code to your app/views/pages/home.html.erb
<%= form_for #form do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :message %>
<%= f.text_area :message %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
And that´s it, you have your build in contact form.
This code is collected from one of my gems on github:
https://github.com/mattherick/contact_form
For testing you can add this gem to your gemfile and run the files generators, described in the github readme.