Validation error messages not showing in form view - ruby-on-rails

I have a simple model :
class Property < ApplicationRecord
belongs_to :user
has_many :invoices, dependent: :destroy
has_many :tenants, dependent: :destroy
validates :street, presence: true, length: { maximum: 50}
validates :city, presence: true, length: { maximum: 50}
validates :zip, presence: true, length: { maximum: 10}
validates :rent, presence: true, length: { maximum: 50}
def receivable
(self.rent.to_i + self.charges.to_i)
end
end
When trying in the console, the validation errors come as expected:
[2] pry(main)> prop = Property.new(street:"zzz")
=> #<Property:0x007fb99cde1cc0 id: nil, number: nil, streetype: nil, street:
"zzz", city: nil, zip: nil, rent: nil, charges: nil, user_id: nil, created_at:
nil, updated_at: nil>
[3] pry(main)> prop.save
(0.3ms) BEGIN
(0.8ms) ROLLBACK
=> false
[4] pry(main)> prop.errors.full_messages
=> ["User must exist", "City can't be blank", "Zip can't be blank", "Rent can't
be blank"]
Here is the controller:
def new
#user = current_user
#property = #user.properties.build
end
def create
#user = current_user
#property = #user.properties.create(property_params)
#property.user_id = current_user.id
if #property.save
flash[:notice] = "Nouveau Bien créé !"
redirect_to user_properties_path
else
redirect_to new_user_property_path
end
end
And here is the form view:
<div class="container center">
<div class="row white">
<div">
<h2>Nouveau bien</h2>
<%= simple_form_for([#user, #property]) do |j| %>
<%= j.input :number, label:"Numéro" %>
<%= j.input :streetype, label: "Laisser vide si nécessaire", collection: ["
","rue","boulevard","allée"] , prompt: "Choisir" %>
<%= j.input :street, label:"Nom" %>
<%= j.input :city, label:"Commune / Ville" %>
<%= j.input :zip, label:"Code Postal" %>
<%= j.input :rent, label:"Montant du Loyer" %>
<%= j.input :charges, label:"Montant des charges" %>
<br>
<%= j.submit 'Créer', class: "form-control btn btn-info" %>
<% end %>
</div>
</div>
</div>
When omitting one of the fields on purpose, the controller redirect to the correct form viw but validation error messages are not present. They use to show up but they disapeared for some reason.
Any idea why?
Thank you!

instead of redirect_to new_user_property_path in else block, you should
render 'new'
Reason: redirect instructs the browser to make the new request, because of which you end up loosing the context of #property object with it's errors. It actually makes a fresh request to new action. render will continue with the current action (which is create in this case) and render the response in new view with #property, errors and previous form body.

Related

Create multiple records in rails with collection_select

I am trying to build a messaging system where the user can select multiple recipients, and I would like to system to create a message for each of them. So far I got the controller like:
def create
#listmail = params[:recipient_ids]
#listmail.each do |v|
#message = current_user.messages.build(:title, :description, :user_id, recipient_id: v, :recipient_email, :tag_id, :industry, :strategy, :position, :aum)
#message.save!
end
if #message.save
redirect_to messages_path
else
render 'new'
end
end
The view:
<%= simple_form_for #message do |f| %>
<%= f.collection_select(:recipient_id, User.all, :id, :full_name, {}, class: "selectpicker", title: "Choose recipent", multiple: true, data: { style: "form-control", size: "20", width: "100%" }) %>
<%= f.input :title, label: "Message Title" %>
<%= f.cktext_area :description, label: "Message Body" , :input_html => {:rows => 15} %>
<%= f.button :submit, :class => 'btn-custom' %>
<% end %>
But I get the error:
/Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:40: syntax error, unexpected ',', expecting => ...ipient_id: v, :recipient_email, :tag_id, :industry, :strateg... ... ^ /Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:54: syntax error, unexpected keyword_end, expecting end-of-input
What am I not doing well please?
/Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:40:
syntax error, unexpected ',', expecting => ...ipient_id: v,
:recipient_email, :tag_id, :industry, :strateg... ...
You are passing an invalid hash to the build method. The hash must be a combination of key-value pairs. For example
Not valid:
h = {:email, :name, user: 1}
SyntaxError: (irb):4: syntax error, unexpected ',', expecting =>
h = {:email, :name, user: 1}
^
Valid:
h = {email:"", name: "", user: 1}
=> {:email=>"", :name=>"", :user=>1}
Solution:
You should change your hash to key-value pairs with the params that are coming to the create method. Usually this was the case before Rails 4. In Rails4, strong params were introduced. If you are using Rails 4+, you should define the strong params like so
def create
#listmail = params[:recipient_ids]
#listmail.each do |v|
#message = current_user.messages.build(message_params)
#message.recipient_id = v
#message.save!
end
if #message.save
redirect_to messages_path
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:title, :description, :user_id, :recipient_id, :recipient_email, :tag_id, :industry, :strategy, :position, :aum)
end
Moreover,
#listmail = params[:recipient_ids]
should be
#listmail = params[:message][:recipient_id]

How to change change error messages on rails

My view:
<div class="form-group">
<% if #product.errors.details[:amount].any? %>
<div class="has-error">
<%= f.label "#{t('product.shineer_irsen')}", class: 'control-label' %>
<%= f.number_field :amount, value: 0, min: 0, class: "form-control" %>
</div>
<% else %>
<%= f.label "#{t('product.shineer_irsen')}", class: 'control-label' %>
<%= f.number_field :amount, value: 0, min: 0, class: "form-control" %>
<% end %>
</div>
I want to validate amount in input field and i want to change its error message into my native language.
Now, error message is
error message
How to change it? please help me.
Product model:
class Product < ApplicationRecord
belongs_to :item
belongs_to :user
belongs_to :branch
validates :amount, numericality: {greater_than_or_equal_to: 0}
def item_name
item.try(:name)
end
def item_name=(query)
self.item = Item.find_by_name(query) if query.present?
end
def amount=(new_value)
if read_attribute(:amount)
#old_amount = read_attribute(:amount)
write_attribute(:amount, new_value.to_i + #old_amount)
else
write_attribute(:amount, new_value.to_i)
end
end
end
some line of local/mn.yml
activerecord:
attributes:
...
errors:
models:
subcategory:
attributes:
category_id:
invalid: "ahaha"
blank: "хоосон байж болохгүй"
category:
blank: "сонгоогүй байна."
product:
attributes:
amount:
greater_than_or_equal_to: 'Оруулах утга 0-ээс их байх ёстой.'
I suppose you want to translate "Value must be grater than or equal to 0", if that's the case, what you need to do is create a translation for that on the locale file. In Spanish will be something like this:
# config/locales/es.yml
es:
activerecord:
errors:
models:
product:
attributes:
amount:
greater_than_or_equal_to: 'What ever you want to say'
Depending on your native language, you have to create the file and define the message, I think you are doing it already, because you are using translations:
#{t('product.shineer_irsen')}
You can find more information here:
http://guides.rubyonrails.org/i18n.html#translations-for-active-record-models
You can customize the error message that you get from a model validation, in this case you need to add to your Model:
validates :age, numericality: {greater_than_or_equal_to: 0, message: 'Este campo tiene que ser positivo' }
With this, you dont need to change the view.

Creating new record fails to save relationship_id

An organization has many members, and a relationship has been created between both models. A member of an organization is allowed to create additional members for that specific organization. This works fine. A system admin can go to the profile of any organization and then click 'create new member' to create a new member that organization. However, currently for the admin the organization_id does not save with the newly created member, thereby causing errors. Does anyone have an idea why the organization_id does not save?
Members controller:
def new
if current_user.admin?
if params[:organization_id].nil?
flash[:danger] = "Please select an organization first"
redirect_to organizations_path
else
#organization = Organization.find(params[:organization_id])
#member = #organization.members.build
end
else
#member = current_organization.members.build
end
end
def create
if current_user.admin?
#member = Member.new(new_params)
else
#member = current_organization.members.build(new_params)
end
if #member.save
#member.send_activation_email
flash[:success] = "A confirmation email will be sent to the new user."
redirect_to member_url(#member)
else
render 'new'
end
end
private
def new_params
params.require(:member).permit(:email,
:username,
:password,
:password_confirmation)
end
Members new view:
<%= form_for(#member) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<% if current_user.admin? %>
<%= f.text_field :organization_id, placeholder: 'Organization id', autocomplete: 'off', class: 'form-control', disabled: "disabled" %>
<% end %>
<%= f.email_field :email, placeholder: 'Email', autocomplete: 'off', class: 'form-control' %>
<%= f.text_field :username, maxlength: 15, placeholder: 'Username', autocomplete: 'off', class: 'form-control' %>
<%= f.password_field :password, placeholder: 'Password', autocomplete: 'off', class: 'form-control' %>
<%= f.password_field :password_confirmation, placeholder: 'Confirm password', autocomplete: 'off', class: 'form-control' %>
<%= f.submit "Sign up", class: "formbutton btn btn-default" %>
<% end %>
The organization profile view contains the following link to the member new view:
<%= link_to image_tag("add.png", title: "add member", height: '15'), new_member_path(organization_id: #organization.id) %>
Part of the members model:
belongs_to :organization
default_scope -> { includes(:organization).order('organizations.org_name , username') }
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email, :downcase_username
before_create :create_activation_digest
#validates :organization_id, presence: true # Commented this out because of a joined form that doesn't work with this validation.
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
VALID_USERNAME_REGEX = /\A[a-zA-Z0-9_-]+\z/i
validates :username, presence: true,
length: { in: 6..15 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
In your def new_params, you are not permitting :organization_id.
If this is for security reasons, you can update your create action as follows:
def create
if current_user.admin?
#member = Member.new(new_params)
#member.organization_id = params[:member][:organization_id]
else
....
end
Also in your form, if you disable a field, it won't be sent as a params. You should add a hidden_field for :organization_id.
<% if current_user.admin? %>
<%= f.text_field :organization_id, placeholder: 'Organization id', autocomplete: 'off', class: 'form-control', disabled: "disabled" %>
<%= f.hidden_field :organization_id, value: #organization.id %>
<% end %>
The problem turned out to be disabled: "disabled" in the form. A disabled field does not get send on submit. Changing it to readonly: "readonly" solved it. See: What's the difference between disabled="disabled" and readonly="readonly" for HTML form input fields?

Ruby on Rails - how do I remove a post once a date has passed?

I currently have a jobs listing site built with Ruby on Rails, on the add jobs page, one of the inputs is the application date in by/job expiry date field ( <%= job.expirydate %> ). I need to add code which will remove the whole listing from view once that date has passed. At the moment the input field for the expiry dat is just a text input, would this need to be changed and if so how? I'm new to Rails so please forgive my knowledge.
index.html.erb -
<% #jobs.each do |job| %>
<div class="job">
<h2><%= link_to job.position, job %></h2>
<ul class="entry_list">
<li>Posted on: <%= job.created_at.strftime("#{job.created_at.day.ordinalize} %B %Y") %></li>
<li>Company: <%= job.company %></li>
<li>Salary: <%= job.salary %></li>
<li>Contract Type: <%= job.contract %></li>
<li>City: <%= job.city %></li>
<li>Applications in by: <%= job.expirydate %></li>
<li>Job Type: <%= job.jobtype %></li>
</ul>
</div>
<% end %>
new.html.erb -
<%= simple_form_for #job, html: { multipart: true } do |form| %>
<h2>Job Position:</h2>
<%= form.input :position, input_html: { maxlength: 60 }, placeholder: "Job Position", label: false %>
<%= form.input :company, input_html: { maxlength: 60 }, placeholder: "Company name", label: false %>
<%= form.input :salary, input_html: { maxlength: 60 }, placeholder: "Salary", label: false %>
<%= form.input :contract, input_html: { maxlength: 60 }, placeholder: "Contract Type", label: false, collection: ['Full time', 'Part time', 'Internship'], prompt: "Contract Type" %>
<%= form.input :city, input_html: { maxlength: 60 }, placeholder: "City", label: false %>
<%= form.input :expirydate, input_html: { maxlength: 60 }, placeholder: "Expiry date", label: false %>
<%= form.input :jobtype, input_html: { maxlength: 60 }, placeholder: "Job Type", label: false, collection: ['Advertising', 'Art Direction', 'Artworker', 'Copywriting', 'Digital Design', 'Digital Developer', 'Editorial', 'Graphic Design', 'Miscellaneous', 'Motion Design/Animation', 'PR and Marketing', 'Project Management', 'Studio Management'], prompt: "Job Type" %>
<%= form.input :description, input_html: { maxlength: 60 }, placeholder: "Full job description", label: false %>
<%= form.input :apply, input_html: { maxlength: 60 }, placeholder: "How to apply", label: false %>
<h2>Your Contact Details:</h2>
<%= form.input :contactname, input_html: { maxlength: 60 }, placeholder: "Contact Name", label: false %>
<%= form.input :contactemail, input_html: { maxlength: 60 }, placeholder: "Contact Email", label: false %>
<%= form.input :contactphone, input_html: { maxlength: 60 }, placeholder: "Contact Telephone", label: false %>
<%= form.input :human_sum, label: 'What is 1+1?' %>
<%= form.button :submit %>
<% end %>
jobs_controller.rb -
class JobsController < ApplicationController
respond_to :html, :js
def index
#jobs = Job.page(params[:page]).per(20).order(created_at: :desc)
end
def new
#job = Job.new
end
def show
#job = Job.find(params[:id])
end
def create
#job = Job.new(params.require(:job).permit(:human_sum, :position, :company, :salary, :companywebsite, :contract, :city, :expirydate, :jobtype, :description, :apply, :contactname, :contactemail, :contactphone, ))
if #job.save
redirect_to root_path
else
render "new"
end
end
end
job.rb -
class Job < ActiveRecord::Base
validates :position, presence: true
validates :company, presence: true
validates :salary, presence: true
validates :companywebsite, presence: true
validates :contract, presence: true
validates :city, presence: true
validates :expirydate, presence: true
validates :jobtype, presence: true
validates :description, presence: true
validates :apply, presence: true
validates :contactname, presence: true
validates :contactemail, presence: true
validates :contactphone, presence: true
attr_accessor :human_sum
validate :not_a_bot
private
def not_a_bot
if human_sum.to_i != 2
errors.add(:human_sum, 'Get out, you bot!')
end
end
scope :by_contract, -> (contracts) { where(:contract => (contracts|| Job.uniq.pluck(:contract)) ) }
scope :by_jobtype, -> (jobtypes) { where(:jobtype => (jobtypes|| Job.uniq.pluck(:jobtype)) ) }
end
You can change your index action in your controller to something like this:
Model.find(:all, :conditions => [job.expirydate < Datetime.now])
If you want to delete old records you can create a file for the task:
# lib/tasks/delete_old_records.rake
namespace :delete do
desc 'Delete records older than 60 days'
task :old_records => :environment do
Model.where('created_at > ?', 60.days.ago).each do |model|
model.destroy
end
# or Model.delete_all('created_at > ?', 60.days.ago) if you don't need callbacks
end
end
Run with:
RAILS_ENV=production rake delete:old_records
Schedule it to run with cron (every day at 8am in this example):
0 8 * * * /bin/bash -l -c 'cd /my/project/releases/current && RAILS_ENV=production rake delete:old_records 2>&1'
You can also use the [whenever][1] gem to create and manage your crontab on deploys:
every 1.day, :at => '8:00 am' do
rake "delete:old_records"
end
I would make a rake task that deletes all the old posts, and then run it from cron or some other scheduler at regular intervals, eg at 2am every day.
EDIT - although, looking at your question some more, i don't think you actually want to delete them. I think you just want to not show them on the index page. Confusing use of the word "remove" there :)
To limit the display to active records, add a scope to the model:
scope :current, -> { expirydate >= Date.current }
and add that to your controller:
#jobs = Job.current.page(params[:page]).per(20).order(created_at: :desc)
2 things:
1) only list the non-expired jobs
def index
#jobs = Job.where('expirydate >= ?', Date.today).page(params[:page]).per(20).order(created_at: :desc)
end
2) Enhance your text input for expirydate with an interactive datepicker.
The rails built in date pickers aren't very nice as they don't use javascript. There's lots of solutions for this depending on which javascript library you use. For jquery for example see http://jqueryui.com/datepicker/

trying to find an user by email an get "Called id for nil"

Hi I'm working on a reset password action. But after click the button I get this error:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Here is my password_reset_controller
class PasswordResetsController < ApplicationController
layout "sessions"
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "#{user.id}Las instrucciones para reestrablecer la contrasena fueron enviadas."
end
end
and Here is my user model
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64
self.password_reset_at = Time.zone.now
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
this is the view:
<% provide(:title, "Reiniciar Password") %>
<div class="row">
<div class="span4">
&nbsp
</div>
<div class="span4" id="login-box">
<div id="login-controls">
<%= link_to(image_tag("logo.png"), root_path) %>
<br>
<br>
<%= form_for(:password_resets, url: password_resets_path) do |f| %>
<%= f.text_field :email, :placeholder => "Correo Electronico", :tabindex => 1, :style => "height:25px;" %>
<%= f.button "<i class=\"icon-lock icon-white\"></i> Reiniciar Password".html_safe, :tabindex => 2, class: "btn btn-warning", :style => "width:220px;margin-bottom:5px;" %>
<% end %>
</div>
</div>
<div class="span4">
</div>
</div>
I don't understan why I can't find the user; I try to do the same at rails console and I can find the user by email, but I can generate the password_reset_token.
Please I appreciate your help.
Thanks
use params[:password_resets][:email]
Please do User.all and see. check on which user record you invoked the password_reset_token method
This means that there is no user in your database with this email.
Use,
user = User.find_by_email!(params[:email])
method with a bang (!) will trigger an exception. find_by_email returns a nil object if the email was not found

Resources