Having following code:
class MyModel < ActiveRecord::Base
before_create :do_process
def do_process
#I want to print here everything that came to this method
self.my_stuff = my_stuff
end
Say we have model with name and description attributes and
I'm going into console and enter something like
MyModel.create! name: 'test', description: 'test'
So how can I view what arguments passed to method do_process?
You can do it this way:
def do_process(*args)
puts args
# body of method
end
It seems that what you really want is to see the attributes of the object as it enters the do_process method. For that, you can use the attributes method:
def do_process
$stderr.puts attributes
self.my_stuff = my_stuff
end
This is a two parter. I'd be happy with either of the approaches below or other suggestions.
I'd like to be able to retrieve records/objects using my model by passing it a search term and having it look for that search term in any field in the model, or any field that the model deems viable. So, as an example:
class Product < ActiveRecord::Base
...
def search_all_fields(search_term)
return search_term.length == 0 ? nil : Product.where("serial_number like :find_me", { :find_me => search_term })
end
end
This is from a Product model. The same function in the Company model might look like:
class Company < ActiveRecord::Base
...
def search_all_fields(search_term)
return search_term.length == 0 ? nil : Company.where("customer_number like :find_me or name like :find_me", { :find_me => search_term })
end
end
I would love a "railsy" way to do this, such as "find_by_looking_everywhere" but I haven't been able to find such a thing. I've found lots of suggestions for searching a single field for multiple values, but not searching multiple fields for a single value. So that's "Part 1," is there a "railsy" way to do this?
"Part 2" ... using the code above, why am I getting the following exception?
undefined method `search_all_fields` for #<Class:0xa38f2ac>
I'm calling the methods using #products = Product.search_all_fields("xy3445") or #companies = Company.search_all_fields("high")?? The trace shows that the exception is being raised by just a generic class. It doesn't say #<Product...> or #<Company...>
I'm a little lost... any and all help appreciated.
Thanks, gang.
Your method is an instance method (the Model need to be instanciated to access this method). You need a Class method (means you don't need an instance of Company to call it, like the methods where(), find() etc).
class Company < ActiveRecord::Base
def say_hello
return "Hello world!"
end
end
This method say_hello can only be called from an instance of Company (instance method):
company = Company.first
company.say_hello #=> "Hello world!"
# but this will raise a NoMethodError:
Company.say_hello #=> NoMethodError
In order to define a method as a class method, you can do the following:
class Company < ActiveRecord::Base
def self.say_hello
return "Hello world!"
end
# OR you can use the name of the model instead of the self keyword:
def Company.say_hello
return "HEllo World!"
end
end
Now you can do:
Company.say_hello
#=> "HEllo World!"
# but this will fail:
Company.first.say_hello
#=> NoMethodError
I have been looking for over an hour on Internet and I can't find anything about this.
I am creating filters for data of a website and currently these are handled by a case statement
class MyClass
attr_accessor :attribute
def self.function(value)
query = case value
when "open" then "Open"
...
end
where(:attribute => query)
end
end
Because of various reasons (i.e. dynamic instead of hard coding the filters) I want to create a model out of this with a getter and setter, but I can't get this to work
My new function:
def self.function(value)
Attribute.name = value
where(:attribute => Attribute.name)
end
My new model:
class Attribute
attr_accessor :name
end
And the test:
it "should set the attribute to 'hello'" do
MyClass.function("hello")
Attribute.name.should eql "hello"
end
gives an error:
Failure/Error: Myclass.function("hallo")
NoMethodError:
undefined method `name=' for Attribute:Class
Any help would be appreciated
This is because the attr_accessor is defining instance method (ie: method that works on an instance of Attribute) and you try to use it as class method (ie: Attribute.name).
You may rewrite your function this way :
def self.function(value)
attribute = Attribute.new
attribute.name = value
where(:attribute => attribute.name)
end
I'm attempting to create a custom validation for one of my models in Rails 2.3.5, but I keep recieving the following error everytime I run my testing suite:
`method_missing_without_paginate': undefined local variable or method `validates_progression'
app/models/project.rb
class Project < ActiveRecord::Base
...
validates_progression
def validates_progression
true # stubtastic!
end
end
I can't seem to make much of this~
It doesn't work because you are defining a method with instance scope and you are trying to call it within the class scope. You have two alternatives:
Instance Scope
class Project < ActiveRecord::Base
validate :validates_progression
def validates_progression
true # stub
end
end
Class scope
class Project < ActiveRecord::Base
def self.validates_progression
true # stub
end
# Be sure to define this method before calling it
validates_progression
end
The second alternative doesn't really makes sense unless you want to wrap an other filter.
class Project < ActiveRecord::Base
def self.validates_progression
validates_presence_of :progression
validates_length_of ...
end
# Be sure to define this method before calling it
validates_progression
end
Otherwise, go with the first solution.
The pagination reference is a red herring. The clue is the 'without'. The will paginate gem has aliased the existing method_missing method and called it method_missing_without_pagination. So, the problem is a standard missing method error.
The method is missing because it is a) not defined when you call it and b) not in the correct scope (you are trying to call an instance method in the scope of the class).
You can add your custom validation by using validate with the symbol for your validation method:
validate :validates_progression
def validates_progression
true
end
For example, if I have a user model and I need to validate login only (which can happen when validating a form via ajax), it would be great if I use the same model validations defined in the User model without actually instantiating a User instance.
So in the controller I'd be able to write code like
User.valid_attribute?(:login, "login value")
Is there anyway I can do this?
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.)
Thank you Milan for your suggestion. Inspired by it I created a simple module one can use to add this functionality to any class. Note that the original Milans suggestion has a logic error as line:
return mock.errors.has_key?(attr)
should clearly be:
return (not mock.errors.has_key?(attr))
I've tested my solution and it should work, but ofc I give no guarantees. And here's my glorious solution. Basically a 2-liner if you take away the module stuff.. It accepts method names as stings or symbols.
module SingleAttributeValidation
def self.included(klass)
klass.extend(ClassMethods)
end
module ClassMethods
def valid_attribute?(attr, value)
mock = self.new(attr => value)
(not mock.valid?) && (not mock.errors.has_key?(attr.class == Symbol ? attr : attr.to_sym))
end
end
end
To use your standard validation routines:
User.new(:login => 'login_value').valid?
If that does not work for you, build a custom class method for this:
class User < ActiveRecord::Base
validate do |user|
user.errors.add('existing') unless User.valid_login?(user.login)
end
def self.valid_login?(login)
# your validation here
!User.exist?(:login=> login)
end
end
I had a hell of a time getting this to work in Rails 3.1. This finally worked. (Not sure if it's the best way to do it, I'm kind of a newb.). The problem I was having was that value was being set to type ActiveSupport::SafeBuffer, and was failing validation.
def self.valid_attribute?(attr, value)
mock = User.new(attr => "#{value}") # Rails3 SafeBuffer messes up validation
unless mock.valid?
return (not mock.errors.messages.has_key?(attr))
end
return true
end
I have gone with the custom class solution but I just wanted to make sure there was no better way
class ModelValidator
def self.validate_atrribute(klass, attribute, value)
obj = Klass.new
obj.send("#{attribute}=", value)
obj.valid?
errors = obj.errors.on(attribute).to_a
return (errors.length > 0), errors
end
end
and I can use it like
valid, errors = ModelValidator.validate_attribute(User, "login", "humanzz")
class User < ActiveRecord::Base
validates_each :login do |record, attr, value|
record.errors.add attr, 'error message here' unless User.valid_login?(value)
end
def self.valid_login?(login)
# do validation
end
end
Just call User.valid_login?(login) to see if login itself is valid
An implementation of the 'valid_attribute' method you are suggesting:
class ActiveRecord:Base
def self.valid_attribute?(attribute, value)
instance = new
instance[attribute] = value
instance.valid?
list_of_errors = instance.errors.instance_variable_get('#errors')[attribute]
list_of_errors && list_of_errors.size == 0
end
end
How about:
User.columns_hash.has_key?('login')