Rails : test if object is ActiveRecord - ruby-on-rails-3

How could I test if var is an ActiveRecord object ?
I tried
if var[:id]
# ==> Activerecord
else
# ==> Other object
end
But I get TypeError: can't convert Symbol into Integer.

You can check the ancestors of your class like so:
var.class.ancestors.include?(ActiveRecord::Base)
or you can just compare the two classes:
if var.class < ActiveRecord::Base
# do something
end

Related

Not able to overwrite object properties in "create" method

I have a simple table for storing users accounts information (emails and passwords) with two additional columns:
is_active - says if user account is enable or disabled - the column
type is boolean and in the context of DB2 it is mapped with
decimal(1)
registration_date - says when the user was created - the column
type is datetime and in the context ofDB2 it is mapped with
datetime
As this fields will not be set by the user, I have deleted their inputs from the users _form.
I want to populated this fields in my users controller as follows:
def create
#security_user = SecurityUser.new(params[:security_user])
#security_user.is_active = 0
#security_user.registration_date = DateTime.now
...
end
But I can not pass the validations that I have in the model. They looks like:
class SecurityUser < ActiveRecord::Base
# Loading custom validators
require 'lib/date_format_validator'
...
# Accessible columns
...
# Relationships
...
# Validations
validates :is_active, inclusion: { in: 0..1, message: "only '0' and '1' allowed"}, presence: true
validates :registration_date, date_format:true , presence: true
end
where the 'lib/date_format_validator' looks like follows:
class DateFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
if (DateTime.parse(value) rescue ArgumentError) == ArgumentError
object.errors[attribute] << (options[:message] || "is not valid datetime")
end
end
end
What I am doing wrong?
EDIT: The screenshot below displays the errors:
EDIT2: Sam Ruby's answer helps me to finish with something like this for my custom validator method:
class DateFormatValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value.kind_of? DateTime || (DateTime.parse(value) rescue ArgumentError) != ArgumentError
object.errors[attribute] << (options[:message] || "is not valid datetime")
end
end
end
and to transform the validates method for the is_active column as follows:
validates :is_active, inclusion: { in: [ true, false ], message: "only 'true' and 'false' allowed"}
because as it is said in the official documentation:
Since false.blank? is true, if you want to validate the presence of a boolean field you should use validates :field_name, :inclusion => { :in => [true, false] }.
The problem is that you are trying to validate the ActiveRecord object as if the columns are of type String. But since you have defined your columns as boolean and datetime, what you will be validating will be of type TrueClass, FalseClass or ActiveSupport::TimeWithZone.
In other words, the values are already parsed.
true is never 0 or 1.
DateTime.parse(DateTime.now) will always raise ArgumentError
If you want to validate the unparsed values, do so in the controller.

Rails 3: As json with include option does not takes into account as_json redefinition for included association

I've got two models.
Class ModelA < ActiveRecord::Base
has_many :model_bs
end
Class ModelB < ActiveRecord::Base
belongs_to :model_a
def as_json(options = {})
{
:whatever => 'hello world'
}
end
end
When I call model_a.as_json(:include => :model_b), I want it to return a json which includes all model_bs, which it does, but employing my as_json redefinition, which it does not as it just uses the default one. Is there any way to use my own method rather than the original one? Thanks
In Rails 3, as_json method invokes serializable_hash to obtain the attributes hash. And they share the same 'options' parameter. In your case, overwritting serializable_hash would give the expected result.
def serializable_hash(options = {})
{:whatever => 'hello world'}
end
But, My suggestion is that instead of overwriting the convention, operate on the result of "super", which is like:
def serializable_hash(options = {})
hash = super
has[:name] = "hello world"
hash
end

How can I troubleshoot this JSON method in DataTables gem?

I'm trying to implement the Railscast 340 that demos how to use DataTables, which looks like an awesome gem for my project.
My model is different, of course; but the datatables class the Mr Bates builds (very quickly), in order to do server-side processing, is rather complicated to follow. I got the source code, and basically attempted to follow along. My view comes up with zero records (but there are > 10,000 records), but does not break.
However, here is what the error message output from the rails server says just before it stops:
NameError (undefined local variable or method `genotypes' for #<GenotypesDatatable:0xa9e852c>):
app/datatables/genotypes_datatable.rb:12:in `as_json'
app/controllers/genotypes_controller.rb:8:in `block (2 levels) in index'
app/controllers/genotypes_controller.rb:6:in `index'
Just before this, there appears to be this JSON error, which starts:
Started GET "/genotypes.json?sEcho=1&iColumns=8&sColumns=&iDisplayStart=0&iDisplayLength=10&mDataProp_0=...
The relevant part of the genotypes controller looks like this:
def index
respond_to do |format|
format.html
format.json { render json: GenotypesDatatable.new(view_context) }
end
end
And my genotypes model looks like:
class Genotype < ActiveRecord::Base
attr_accessible :allele1, :allele2, :run_date
belongs_to :gmarkers
belongs_to :gsamples
end
My datatables class is given below. This is from Mr Bates code, modified (most likely incorrectly) to replace his Products model with my Genotypes model:
class GenotypesDatatable
delegate :params, :h, :link_to, to: :#view
def initialize(view)
#view = view
end
def as_json(options = {})
{
sEcho: params[:sEcho].to_i,
iTotalRecords: Genotype.count,
iTotalDisplayRecords: genotypes.total_entries,
aaData: data
}
end
private
def data
genotypes.map do |genotype|
[
link_to(genotype.name, genotype),
h(genotype.category),
h(genotype.released_on.strftime("%B %e, %Y")),
genotype.run_date
]
end
end
def Genotypes
#Genotypes ||= fetch_Genotypes
end
def fetch_genotypes
genotypes = Genotype.order("#{sort_column} #{sort_direction}")
genotypes = genotypes.page(page).per_page(per_page)
if params[:sSearch].present?
genotypes = genotypes.where("name like :search or category like :search", search: "%#{params[:sSearch]}%")
end
genotypes
end
def page
params[:iDisplayStart].to_i/per_page + 1
end
def per_page
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
end
def sort_column
columns = %w[gmarker gsample allele1 allele2 run_date]
columns[params[:iSortCol_0].to_i]
end
def sort_direction
params[:sSortDir_0] == "desc" ? "desc" : "asc"
end
end
Any hints on how to troubleshoot (or fix!) this error much appreciated! (Getting this working for my project would be awesome!)
TIA,
rixter
I'm not sure if this is it, but your class has a Genotype method with capital G, it should be all lowercase.

Can I use common ActiveRecord scopes(scope) with module in Rails?

In rails3, I make same scopes in model. for example
class Common < ActiveRecord::Base
scope :recent , order('created_at DESC')
scope :before_at , lambda{|at| where("created_at < ?" , at) }
scope :after_at , lambda{|at| where("created_at > ?" , at) }
end
I want to split common scopes to module in lib. So I try like this one.
module ScopeExtension
module Timestamps
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
scope :recent , lambda{order('created_at DESC')}
scope :before_at , lambda{|at| where("created_at < ?" , at) }
scope :after_at , lambda{|at| where("created_at > ?" , at) }
end
end
and I write this one
class Common < ActiveRecord::Base
include ScopeExtension::Timestamps
end
But Rails show this error.
undefined method `scope' for ScopeExtension::Timestamps::ClassMethods:Module
(I didn't forget auto loading library)
How can I easily reuse common scope feature in active record?
I guess this problem to relate loading sequence. But I don't have any idea to solve.
Please hint me.
I solved this calling the scope on self.included(class):
module Timestamps
def self.included(k)
k.scope :created_yesterday, k.where("created_at" => Date.yesterday.beginning_of_day..Date.yesterday.end_of_day)
k.scope :updated_yesterday, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
k.scope :created_today, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
k.scope :updated_today, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
end
end
In Rails 3 there's no difference between a declared scope and a class method that returns an ActiveRecord::Relation, so it can be more elegant to use a mixin module:
class MyClass < ActiveRecord::Base
extend ScopeExtension::Timestamps
end
module ScopeExtension
module Timestamps
def recent
order('created_at DESC')
end
def before_at(at)
where('created_at < ?' , at)
end
def after_at(at)
where('created_at > ?' , at)
end
end
end
MyClass.after_at(2.days.ago).before_at(1.hour.ago).recent

How to set Mongoid fields from within the class

I am suddenly completely lost with scope of variables in Rails with Mongoid. (Probably due to a lack of coffee).
All I want, is a way to set certain fields from within the application, but the only way I can find to do this, is by calling write_attribute.
class Example
include Mongoid::Document
field :foo
def bar
#foo = "meh"
end
def hmpf
foo = "blah"
end
def baz
write_attribute(:foo, "meh")
end
end
e.bar #=> "meh"
e.foo #=> nil
e.hmpf #=> "blah"
e.foo #=> nil
e.baz #=> [nil, "meh"]
e.foo #=> "meh"
Am I using the scope wrong? Why will running foo = "bar" not set the field from within, it works from outside: e.foo = "blah" works trough the magic methods.
Try adding self to your attribute references when working in your model's instance methods:
def hmpf
self.foo = "blah"
end
Should do the trick.