So I have a object and I want to define a lifecycle hook such as before_create, after_create, etc.
I want to call this after_retire and have it setup so I can do the following:
class User < ActiveRecord::Base
include Active
after_retire :method
def method
#do stuff
end
end
So far I have a module setup like so but I keep getting a method undefined after_retire error on my User model.
module Active
extend ActiveSupport::Concern
included do
define_callbacks :retire
set_callback :retire, :after, :after_retire
default_scope { where(:retired => false) }
scope :retired, where(:retired => true)
end
def retire!
run_callbacks :retire do
update_attribute :retired, true
update_attribute :retired_at, Time.now.to_datetime
end
end
end
How should I be setting this up?
The before/after_callback syntax is handled in ActiveModel::Callbacks through #define_model_callbacks. The raw ActiveSupport::Callbacks will require you to use #set_callback without any syntactic sugar:
module Active
extend ActiveSupport::Concern
included do
define_callbacks :retire
default_scope { where(:retired => false) }
scope :retired, where(:retired => true)
end
def retire!
run_callbacks :retire do
update_attribute :retired, true
update_attribute :retired_at, Time.now.to_datetime
end
end
end
class User < ActiveRecord::Base
include Active
set_callback :retire, :after, :method
def method
#do stuff
end
end
If you want to have the after/before syntax, since you are working with an ActiveRecord (and thus ActiveModel) class, you can use:
module Active
extend ActiveSupport::Concern
included do
define_model_callbacks :retire
default_scope { where(:retired => false) }
scope :retired, where(:retired => true)
end
def retire!
run_callbacks :retire do
update_attribute :retired, true
update_attribute :retired_at, Time.now.to_datetime
end
end
end
class User < ActiveRecord::Base
include Active
after_retire :method
def method
#do stuff
end
end
Related
I am getting an error:
undefined local variable or method `current_admin_user' for #<ActiveAdmin::ResourceDSL
How can I access current_admin_user object here?
ActiveAdmin.register Job do
def quick_filters
if current_admin_user.super_admin?
[:all, :draft, :scheduling, :rejected]
else
[:all, :scheduling, :rejected]
end
end
quick_filters.each do |a|
scope a
end
end
This is working:
controller do
def scoped_collection
#jobs = if current_admin_user.super_admin?
super.includes :trip, :car, :concierge, :creator, :job_template
else
super.where(concierge_id: current_admin_user.id).includes :trip, :car, :concierge, :creator, :job_template
end
end
end
I think this should work:
ActiveAdmin.register Job do
scope :all
scope :draft, :if => proc { current_admin_user.super_admin? }
scope :scheduling
scope :rejected
end
The DSL for setting up scopes is evaluated at server startup time and does not have access to request cycle based data (like the logged in user). To get around this ActiveAdmin has the concept of wrapping code code with proc so that the enclosed code evaluation is deferred to request-cycle-time.
Good luck!
I am trying to setup belongs_to, validates, and default scopes in a module.
module MultiTenancy
class TenantNotSetError < StandardError ; end
def self.included(model)
class << model
belongs_to :tenant
validates :tenant_id, presence: true
default_scope -> {
raise TenantNotSetError.new unless Tenant.current_tenant
where(tenant_id: Tenant.current_tenant.id)
}
def multi_tenanted?
true
end
end
end
end
I keep getting a
NoMethodError: undefined method `belongs_to' for #<Class:User>
error.
What am I doing wrong?
This should work:
def self.included(base)
base.class_eval do
# your code goes here
end
end
The reason it doesn't work is you try to call belongs_to on metaclass of User, not on User.
I'm extending and including those files but still receive: undefined method after_initialize for Play:Class
class Play
extend ActiveModel::Callbacks
extend ActiveModel::Naming
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
include ActiveModel::Conversion
after_initialize :process_data
#...
end
I'm using Rails 4.
I don't know if you need all the ActiveModel overhead, but you could do it with less code:
class Play
include ActiveModel::Model
def initialize(attributes)
super(attributes)
after_initialize
end
private
def after_initialize
...
end
end
Try out following code
class Play
extend ActiveModel::Naming
extend ActiveModel::Callbacks
define_model_callbacks :initialize, :only => :after
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
include ActiveModel::Conversion
attr_accessor :name
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
run_callbacks :initialize do
puts 'initialize callback'
end
end
def attributes
return #attributes if #attributes
#attributes = {
'name' => name
}
end
end
#1.9.2-p290 :001 > Play.new(:name => 'The name')
#initialize callback
# => #<Play:0x00000006806050 #name="The name">
#1.9.2-p290 :002 >
I have the error
undefined method events_and_repeats' for #<Class:0x429c840>
app/controllers/events_controller.rb:11:in `index'
my app/models/event.rb is
class Event < ActiveRecord::Base
belongs_to :user
validates :title, :presence => true,
:length => { :minimum => 5 }
validates :shedule, :presence => true
require 'ice_cube'
include IceCube
def events_and_repeats(date)
#events = self.where(shedule:date.beginning_of_month..date.end_of_month)
return #events
end
end
app/controllers/events_controller.rb
def index
#date = params[:month] ? Date.parse(params[:month]) : Date.today
#repeats = Event.events_and_repeats(#date)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #events }
end
end
What is wrong?
Like Swards said, you called a instance method on a class. Rename it:
def self.events_and_repeats(date)
I am only writting this in an answer because it's too long for a comment,
checkout the ice-cube github page, it strictly says:
Include IceCube inside and at the top of your ActiveRecord model file to use the IceCube classes easily.
Also i think it you don't need the require in your model.
You can do it both ways:
class Event < ActiveRecord::Base
...
class << self
def events_and_repeats(date)
where(shedule:date.beginning_of_month..date.end_of_month)
end
end
end
or
class Event < ActiveRecord::Base
...
def self.events_and_repeats(date)
where(shedule:date.beginning_of_month..date.end_of_month)
end
end
Just for more clarity:
class Foo
def self.bar
puts 'class method'
end
def baz
puts 'instance method'
end
end
Foo.bar # => "class method"
Foo.baz # => NoMethodError: undefined method ‘baz’ for Foo:Class
Foo.new.baz # => instance method
Foo.new.bar # => NoMethodError: undefined method ‘bar’ for #<Foo:0x1e820>
Class method and Instance method
In Rails, you can add a block after a named_scope for additional, context-sensitive methods like so:
class User < ActiveRecord::Base
named_scope :inactive, :conditions => {:active => false} do
def activate
each { |i| i.update_attribute(:active, true) }
end
end
end
In this example, the activate method is being defined not on the User class, but on the ActiveRecord::NamedScope::Scope object.
I have a series of three scopes that need to have identical method definitions. In the interests of not repeating code, how would I abstract that block such that I could define it once and pass it to each named_scope?
Firstly, great question--I didn't know about that feature of named scopes! The following works for me:
class User < ActiveRecord::Base
add_activate = lambda do
define_method "activate" do
each { |i| i.update_attribute(:active, true) }
end
end
named_scope :inactive, :conditions => {:active => false}, &add_activate
end
You can pass the add_activate block as the last argument to any named scopes that need the activate method.
Much better:
http://tuxicity.se/rails/dry/2009/01/04/share-named-scopes-in-rails.html
module NamedScope
def self.included(base)
base.class_eval do
named_scope :inactive, :conditions => {:active => false} do
def activate
each { |i| i.update_attribute(:active, true) }
end
end
end
end
end
Save in your /lib directory (put a require in an initializers in rails 3) and include NamedScope in your User class