Is there a way to validate a specific attribute on an ActiveRecord without instantiating an object first?
Since validations operate on instances (and they use the errors attribute of an instance as a container for error messages), you can't use them without having the object instantiated. Having said that, you can hide this needed behaviour into a class method:
class User < ActiveRecord::Base
def self.valid_attribute?(attr, value)
mock = self.new(attr => value)
unless mock.valid?
return mock.errors.has_key?(attr)
end
true
end
end
Now, you can call
User.valid_attribute?(:login, "login value")
just as you intended.
(Ideally, you'd include that class method directly into the ActiveRecord::Base so it would be available to every model.)
Perform only validation of record (without creating it)
Sure, just call valid?
on the object:
user = User.new
user.valid? #=> false
user.errors #=> 'name missing...'
validate and update single attribute rails
You could validate the attribute by hand and use update_attribute
, that skips validation. If you add this to your User
:
def self.valid_attribute?(attr, value)
mock = self.new(attr => value)
if mock.valid?
true
else
!mock.errors.has_key?(attr)
end
end
And then update the attribute thusly:
if(!User.valid_attribute?('avatar', params[:user][:avatar])
# Complain or whatever.
end
@user.update_attribute('avatar', params[:user][:avatar])
You should get your single attribute updated while only (manually) validating that attribute.
If you look at how Milan Novota's valid_attribute?
works, you'll see that it performs the validations and then checks to see if the specific attr
had issues; it doesn't matter if any of the other validations failed as valid_attribute?
only looks at the validation failures for the attribute that you're interested in.
If you're going to be doing a lot of this stuff then you could add a method to User:
def update_just_this_one(attr, value)
raise "Bad #{attr}" if(!User.valid_attribute?(attr, value))
self.update_attribute(attr, value)
end
and use that to update your single attribute.
How to skip validations while creating a object in activerecord
a = Article.new(title: "sfsfsd")
a.save(validate: false)
Note that save also has the ability to skip validations if passed
validate: false as an argument. This technique should be used with
caution.
http://guides.rubyonrails.org/active_record_validations.html#skipping-validations
How to create validations for initialized variables?
Rails does the validations only if you call valid?
or save
on the model. So if you want it to accept only values for your value when calling those methods, do a custom validation:
class MyClass < ActiveRecord::Base
validate :value_string
#further code
Setup your value validation like that under the protected scope
protected
def value_string
self.errors[:base] << 'Please assign a string to value' unless @value.match(/^\w+$/)
end
These validations won't be called without calling valid?
or save
, like I said before.
If you want value not to be assigned with another value than a word-like-value at any time, there's no other way than to prevent it on initialization:
def initialize(attributes = nil, options = {})
attr_value = attributes.delete(:value) if attributes
@value = attr_value if attr_value && attr_value.match(/^\w+$/)
super
end
EDIT
I would not recommend raising an ActiveRecord
validation error when assigning not accepted values on initialization. Try to raise your own custom error based on ArgumentError
Outside your class
YourError = Class.new(ArgumentError)
Inside your Class
def initialize(attributes = nil, options = {})
attr_value = attributes.delete(:value) if attributes
if attr_value && attr_value.match(/^\w+$/)
@value = attr_value
elsif attr_value
raise YourError.new('Value only accepts words')
end
super
end
and then test it like this
describe Myclass do
it 'should raise an error if value is assigned with something else than a word' do
lambda{ MyClass.new(:value => 1111)}.should raise_error(YourError)
end
it 'should assign the value for words' do
MyClass.new(:value => 'word').value.should == 'word'
end
end
Instantiating an associated model input is available to populate the model attributes (has_one)
Why Credentials belongs to controller? It should belongs to user, and if you use has_one
association, you should use singular noun of credential:
Model
class Credential < ActiveRecord::Base
belongs_to user
...
class User < Active ::Base
has_one :credential, :dependent => :destroy
Controller
In your controller, if you want create new object for form, you only need:
def new
@cred = current_user.build_credential
end
def create
@cred = current_user.build_credential(params[:cred])
if @cred.save
# what you do when creating object success
else
# what you do when creating object failed
end
end
View
In your new.html.erb
in app/views/credentials/
folder, create your form:
<%= form_for @cred do |f| %>
...
<% end %>
To link to new.html.erb
page, in your view create a link_to
:
<%= link_to 'New Credential', new_credential_path %>
Routes
If you want to use RESTful route, In your routes.rb
, add resources for credential you don't have:
resources :credentials
Is there a validation I can use for a specific attribute on all associated records?
Most likely the best way would be to use after_add
callback (an example here), which would set to false all your existing accepted
records via update_all and the latest answer with accepted set to true. It all depends on your logic.
You can also employ some other callbacks such as before_save, before_update and such with the similar functionality depending on your application specifics.
It is not quit a validation, but it will effectively maintain the required state of your model. Besides, the purpose of the validations to warn you when something is not valid, but I guess you want to save your object without such failures, and just enforce a single accepted answer.
Let me know in case you want to stop adding answers after the first one was accepted. In this case it would require a different functionality.
Validate Attribute without saving
You could try checking for specific errors related to the username, in addition to running all validations (you need to in order to get the error messages).
@user = User.new(params[:user])
if @user.invalid? && @user.errors[:username].any?
# yay!
else
# nope
end
You can run that without persisting your user to the database, since none of the methods used (including #new and #valid?) actually save the object.
Related Topics
How to Remove Repeated Spaces in a String
Strong Parameters Require Multiple
Get Server File Path with Paperclip
Capistrano 3 Execute Within a Directory
How to Alias a Class Method in Rails Model
Ruby: "&& Return" VS "And Return"
Ruby $Stdin.Gets Without Showing Chars on Screen
Ruby: How to Generate CSV Files That Has Excel-Friendly Encoding
Clarification on the Ruby << Operator
Convert String to Class Name Without Using Eval in Ruby
How to Get My Aws Lambda to Access Gems Stored in Vendor/Bundle
How to Use a Branch in a Fork of Rails in a Project with Bundler
Getting Devise Sign_In Form into Twitter Bootstrap Modal