I have a session controller which manages login/logout actions.These are not associated with any model. I want to use the validates helper methods with this session controller so that I can use, :maximum, :minimum, etc. conditions for the username and password. But if there is no model, how do I use these validation methods. Also, if I use these helpers it is easy to integrate with my simple_form login page for the error message, similar to which I have done for my user registration page.
If above helper methods are not possible to be used, what alternative I have which is easy to interface with my simple_form?
Validations can be used without creating a model, i.e. a class inheriting from ActiveRecord::Base. You can have a class that includes ActiveModel::Validations and use its methods. For example:
class Session
include ActiveModel::Validations
attr_accessor :username, :password
def initialize(user, pass)
#username = user
#password = pass
end
validates_length_of :username, minimum: 5
validates_length_of :password, minimum: 7
end
And you use like that:
session = Session.new("name", "secret")
session.valid? ## => false
Related
I have a set of custom fields attached to a devise model called Entrant.
I have two forms, one for registration form (three fields) and one which sits in the account area (12 fields). Most of the custom fields area required but only within the form the sits in the account area.
How do I achieve this?
I am using rails 4.2 and ruby 2.1
You can simply specify validations on actions, that is:
validates :name, presence: true, on: :create # which won't validate presence of name on update action
If you ask where to put your custom fields, then generate devise's views and update corresponding ones with these fields.
There are several ways! You could do conditional validations, for instance
class Entrant < ActiveRecord::Base
validate :foo, if: :account_area?
def account_area?
!new_record? # Assumes that Entrant that has already been saved
# is in the account area
end
end
However, it sounds like your needs are advanced enough that you should consider making a Form Object
A form object is an object that accepts parameters, performs validations on that data, then saves a model instance.
class AccountForm
include ActiveModel::Model
include Virtus # Provides AR like attribute functionality and mass assignment
def initialize(entrant)
#entrant = entrant
end
attribute :foo, String
validates :foo, presence: true # This is only used on the account page, so no need to mess with conditional logic
def save
if valid?
persist!
true
else
false
end
end
def persist!
#entrant.update_attributes(foo: self.foo)
end
end
This is just a great example of how non-rails-specific object oriented programming can make your life easier and your app more maintainable. Make a class like above, stick it in app/forms and restart your server. Then in your controller, you'll just pass it the model
class EntrantController < ApplicationController
def update
#form = Form.new(Entrant.find(params[:id]))
#form.attributes = params[:entrant]
if #form.save
redirect_to some_path
else
render "edit"
end
end
end
By default devise only asks for a combination of email/password, you can add other fields by adding a sanitizer (see there -> Devise how to add a addtional field to the create User form?).
If you want to add other fileds to validate, you should create a secondary Entrant controller and add a specific callback to your model.
Typically:
after_update :validate_entrant_form, if: :property_changed?
I hope this will help you.
validates :name, presence: true, if: :condition_holds?
def condition_holds?
# some code here that evaluates to a boolean
end
Maybe this way help you.
Add attribute in devise model : say attr_accessor :validate_certain. In your controller action, devise model instance say #user have to update like this #user.validate_certain = true. and change your appropriate validation conditions in devise model
validates :name, presence: true, if: :validate_certain_changed?
def validate_certain_changed?
validate_certain.present?
end
When I have to do something like this I like to think of it as it validates if something in in the field but you can also take a nil value
Entrant.validates_presence_of(:foo, :allow_nil => true)
I also have this concern when using devise on customer with forms on separate pages updating different set of customer fields
I believe most of the solution works but I was looking for the simplest, easiest and foolproof way to implement the solution
Thus came this.
validates :phone, :country, :postal_code, :street_address, presence: true, allow_nil: true
The allow_nil: true instruct the model to validate the fields ONLY if it exists on the submitted form. If you want more protection, you can use extra para like :on => :update
In controller action I have two parameters: params[:name] and params[:email]. I would like check them. if they not null and haven't some wrong symbols. Why I asking - because I am not sure can I use validation in controller and I don't know how check param for some symbols...use regular function?...Here is my try:
Controller:
validates :name, :presence => true
validates :email, :presence => true
def check
name = params[:name].valid?
email = params[:email].valid?
end
The validation should occur in the model. Remember the controller should only translate HTTP requests into your application actions.
When you are creating an object you are doing it at the Model layer, so the validation should be at this layer, the model.
I am creating a Tumblr alternative to learn how use Rails. I am at the authentication part, and I decided to do it from scratch. I want to allow users to log in using either their username or their email. The user logs in via the Sessions controller but I need to verify if the login is either a valid username or a valid email. So I need to validate data in the Sessions controller using the User model.
I found this answer on SO: How do I validate a non-model form in Rails 3? but it will force me to duplicate the validations. Is that the only way to do it, or is there another way that is cleaner?
The best option I can imagine is creating a module and then including it at your User model and at the object you're going to use for the form:
module AuthenticationValidation
def self.included( base )
base.validates :username, :presence => true
base.validates :email, :presence => true
# add your other validations here
end
end
And then include this module at your models:
class User < ActiveRecord::Base
include AuthenticationValidation
end
class LoginForm
include ActiveModel::Validations
include ActiveModel::Conversion
include AuthenticationValidation
attr_accessor :username, :email
end
And then you have avoided repeating the validation itself.
I have a simple User class with the following validation of name uniqueness:
class User < ActiveRecord::Base
validates :name, :uniqueness => true,
It works great when a new user is created. However, when I check the login form, the user enters his name, and the system says it's already taken which doesn't make any sense.
So I implemented a separate valid_login? method, however I can't turn that unqueness check there:
def valid_login?
validates :name, :uniqueness => false # doesn't work
end
This is my controller's code:
def login
return unless request.post?
#user = User.new(params[:user])
if #user.valid_login?
# Redirect to user's page
end
end
I'm using my own authentication system which is quite simple: I store user's ID + password's hash in the cookies.
How can I turn of certain validation when I don't need it?
I solved this problem with the :if/:unless parameters.
I have a form that allows the user to send a message to an email, and I want to add validation to it. I do not have a model for this, only a controller. How should I do this in Rails?
I was considering doing the validation in the controller, and displaying the errors to the user using the flash object. Is there a better way of doing this?
The best approach would be to wrap up your pseudo-model in a class, and add the validations there. The Rails way states you shouldn't put model behavior on the controllers, the only validations there should be the ones that go with the request itself (authentication, authorization, etc.)
In Rails 2.3+, you can include ActiveRecord::Validations, with the little drawback that you have to define some methods the ActiveRecord layer expects. See this post for a deeper explanation. Code below adapted from that post:
require 'active_record/validations'
class Email
attr_accessor :name, :email
attr_accessor :errors
def initialize(*args)
# Create an Errors object, which is required by validations and to use some view methods.
#errors = ActiveRecord::Errors.new(self)
end
# Required method stubs
def save
end
def save!
end
def new_record?
false
end
def update_attribute
end
# Mix in that validation goodness!
include ActiveRecord::Validations
# Validations! =)
validates_presence_of :name
validates_format_of :email, :with => SOME_EMAIL_REGEXP
end
In Rails3, you have those sexy validations at your disposal :)
For Rails 3+, you should use ActiveModel::Validations to add Rails-style validations to a regular Ruby object.
From the docs:
Active Model Validations
Provides a full validation framework to your objects.
A minimal implementation could be:
class Person
include ActiveModel::Validations
attr_accessor :first_name, :last_name
validates_each :first_name, :last_name do |record, attr, value|
record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
end
end
Which provides you with the full standard validation stack that you
know from Active Record:
person = Person.new
person.valid? # => true
person.invalid? # => false
person.first_name = 'zoolander'
person.valid? # => false
person.invalid? # => true
person.errors.messages # => {first_name:["starts with z."]}
Note that ActiveModel::Validations automatically adds an errors method
to your instances initialized with a new ActiveModel::Errors object,
so there is no need for you to do this manually.