Rails 3: Custom error message in validation - validation

I don't understand why the following is not working in Rails 3. I'm getting "undefined local variable or method `custom_message'" error.
validates :to_email, :email_format => { :message => custom_message }
def custom_message
self.to_name + "'s email is not valid"
end
I also tried using :message => :custom_message instead as was suggested in rails-validation-message-error post with no luck.
:email_format is a custom validator located in lib folder:
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
object.errors[attribute] << (options[:message] || 'is not valid')
end
end
end

Just for reference, this is what I believe is going on. The 'validates' method is a class method, i.e. MyModel.validates(). When you pass those params to 'validates' and you call 'custom_message', you're actually calling MyModel.custom_message. So you would need something like
def self.custom_message
" is not a valid email address."
end
validates :to_email, :email_format => { :message => custom_message }
with self.custom_message defined before the call to validates.

If anyone is interested I came up with the following solution to my problem:
Model:
validates :to_email, :email_format => { :name_attr => :to_name, :message => "'s email is not valid" }
lib/email_format_validator.rb:
class EmailFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
error_message = if options[:message] && options[:name_attr]
object.send(options[:name_attr]).capitalize + options[:message]
elsif options[:message]
options[:message]
else
'is not valid'
end
object.errors[attribute] << error_message
end
end
end

Maybe the method "custom_message" needs to be defined above the validation.

Related

Writing rspec for controllers with params?

I have a controller which has the following method
class <controllername> < ApplicationController
def method
if params["c"]
.....
elsif params["e"]
.....
else
.....
end
end
end
Now, I want to write rspec for the above code.
How can I write separate context for both the params and how will I mention them as a get method.
If I understand your question correctly, you can try approach like this:
RSpec.describe <controllername>, :type => :controller do
describe "GET my_method" do
context "param 'c' is provided"
get :my_method, { "c" => "sample value" }
expect(response).to have_http_status(:success)
end
context "param 'e' is provided"
get :my_method, { "e" => "sample value" }
expect(response).to have_http_status(:success)
end
end
end
Hope it puts you in proper direction.
Good luck!

Rails 4 strong parameters ActiveModel::ForbiddenAttributesError

For some reason in my current controller I am getting ActiveModel::ForbiddenAttributesError even though I believe I am using strong parameters just fine. Albeit I am using permit! for the time being to permit all model attributes. See code below, what am I missing
class HeuristicsController < ApplicationController
def index
#heuristics = Heuristic.order(:name).page params[:page]
#heuristic = Heuristic.new
end
def create
#heuristic = Heuristic.new(params[:heuristic])
if #heuristic.save
redirect_to action: 'index', :flash => {:success => "New heuristic created!" }
else
render 'new'
end
end
def new
#title = "Heuristic"
#heuristic = Heuristic.new
end
private
def heuristic_params
params.require(:heuristic).permit!
end
end
i think you did not fully understand the way that strong-params work...
you have a method
def heuristic_params
params.require(:heuristic).permit!
end
and you are not using it
Heuristic.new(params[:heuristic])

Ruby Sinatra + Sequel constraint error handling

What is the right way to handle exceptions coming from the model in Sequel? Particularly the thing I'm running into is when the unique constraint is applied to the login. The exception in this case appears to be coming from SQLite itself instead of Sequel which means it's not getting handled by "errors".
This is the error I'm getting after trying to create a user with a "non-unique" login:
Sequel::DatabaseError at /user/create
SQLite3::ConstraintException: column login is not unique
file: database.rb location: close line: 97
Here is my abbreviated code:
require 'sinatra'
require 'sequel'
DB.create_table :users do
primary_key :id
String :login, :key => true, :length => (3..40), :required => true, :unique => true
String :hashed_password, :required => true
String :salt
DateTime :created_at, :default => DateTime.now
end
class User < Sequel::Model
# password authentication code
end
get '/user/create' do
slim :user_create
end
post '/user/create' do
user = User.new
user.login = params['login']
user.password = params['password']
if user.save
'User created'
else
tmp = []
user.errors.each do |e|
tmp << (e.join('<br/>'))
end
tmp
end
end
You probably want to use the validation_helpers plugin and use validates_unique :login inside the validate method.
Add the code below to handle sequel errors in sinatra.
The error block in sinatra will handle any errors thrown in one of your routes. You can specify the type of error in the first line in order to only handle those types of errors.
error Sequel::Error do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
If you wanted to handle all errors, you would insert the following block of code.
error Exception do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
You can combine many of these blocks so that you are handling different types of errors differently.
First - use validation plugin
# models/account.rb
Sequel::Model.plugin :validation_helpers
class Account < Sequel::Model
def validate
super
validates_unique :login
end
end
Next - handle error in app
# app.rb
...
begin
Account.create
rescue => e
# do what you need
end
...

Sinatra: DB Authentication with Sessions

I am writing a small sinatra application that I am integrating with Authlogic (following https://github.com/ehsanul/Sinatra-Authlogic-Template)
Everything works except for when I try to login. I get the following error:
NameError at /login
undefined local variable or method `active' for #<User:0x000001040208f0>
I am including the authlogic gem versus including it as a vendor. So my Sinatra app is not exactly the same as the one on Github.
Any and all inquiries will be MUCH appreciated!! Thanks!
Found out my issue.
Here is the model according to the Github page:
class User < ActiveRecord::Base
acts_as_authentic do |c|
# Bcrypt is recommended
#crypto_provider = Authlogic::CryptoProviders::BCrypt
c.perishable_token_valid_for( 24*60*60 )
c.validates_length_of_password_field_options =
{:on => :update, :minimum => 6, :if => :has_no_credentials?}
c.validates_length_of_password_confirmation_field_options =
{:on => :update, :minimum => 6, :if => :has_no_credentials?}
end
def active?
active
end
def has_no_credentials?
crypted_password.blank? #&& self.openid_identifier.blank?
end
def send_activation_email
Pony.mail(
:to => self.email,
:from => "no-reply#domain.tld",
:subject => "Activate your account",
:body => "You can activate your account at this link: " +
"http://domain.tld/activate/#{self.perishable_token}"
)
end
def send_password_reset_email
Pony.mail(
:to => self.email,
:from => "no-reply#domain.tld",
:subject => "Reset your password",
:body => "We have recieved a request to reset your password. " +
"If you did not send this request, then please ignore this email.\n\n" +
"If you did send the request, you may reset your password using the following link: " +
"http://domain.tld/reset-password/#{self.perishable_token}"
)
end
end
I removed all of the mail methods but my script was failing on the active? method because it was looking for an active column in the users table. Since I am unable to append this column to the table (due to data integrity with another system) I simply told my method to return true
My User.rb
class UserSession < Authlogic::Session::Base
end
class User < ActiveRecord::Base
acts_as_authentic do |c|
end
def active?
return true
end
end
Hope this helps someone!

MongoMapper custom validation

I have this ruby class with an array of links. As it is now I'm able to save a Paper object even if the array contains links that are not valid urls. I have a method that runs through the array and validates the urls and returns false if a url is invalid. But I want to get an error message when I try to call Paper.save. Is that possible?
class Paper
include MongoMapper::Document
key :links, Array
validates_presence_of :links
def validate_urls
reg = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix
status = []
links.each do |link|
if link.match(reg)
status.push('true')
else
if "http://#{link}".match(reg)
status.push('true')
else
status.push('false')
end
end
end
if status.include?('false')
return false
else
return true
end
end
end
If you're using MongoMapper from GitHub (which supports ActiveModel), see http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
class Paper
include MongoMapper::Document
key :links, Array
validates_presence_of :links
validate :validate_urls
def validate_urls
reg = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix
status = []
links.each do |link|
if link.match(reg)
status.push('true')
else
if "http://#{link}".match(reg)
status.push('true')
else
status.push('false')
end
end
end
if status.include?('false')
# add errors to make the save fail
errors.add :links, 'must all be valid urls'
end
end
end
Not sure if that code works with the 0.8.6 gem but it might.
Also, it doesn't apply in this case but if it weren't an array you could smash it all into a single line:
key :link, String, :format => /your regex here/

Resources