NameError: undefined method `xyz' for class `State' in rails 4 - ruby-on-rails

In model:
class State < ActiveRecord::Base
belongs_to :country
alias_method :abc, :xyz
def self.xyz
end
end
In log:
1.9.3-p551 :005 > State.abc
NameError: undefined method 'xyz' for class 'State'
I am new to alias_method in rails. Please help me out.

This is nothing to do with Rails, alias_method is part of ruby itself, which you really should learn before trying to use Rails.
Your problem here is that you've defined xyz as a class/singleton method, but alias_method called as you've done works on instance methods.

You can try the following :
class State
def self.xyz
ap 'inside'
end
self.singleton_class.send(:alias_method, :abc, :xyz)
end
Following should work :
>> State.xyz
>> State.abc

Related

Undefined class method using Rails Concerns

I did everything pretty much as described here: question
But I keep getting error:
NoMethodError: undefined method `parent_model' for Stream (call 'Stream.connection' to establish a connection):Class
In model/concerns faculty_block.rb
module FacultyBlock
extend ActiveSupport::Concern
included do
def find_faculty
resource = self
until resource.respond_to?(:faculty)
resource = resource.parent
end
resource.faculty
end
def parent
self.send(self.class.parent)
end
end
module ClassMethods
def parent_model(model)
##parent = model
end
end
end
[Program, Stream, Course, Department, Teacher].each do |model|
model.send(:include, FacultyBlock)
model.send(:extend, FacultyBlock::ClassMethods) # I added this just to try
end
In initializers:
require "faculty_block"
method call:
class Stream < ActiveRecord::Base
parent_model :program
end
It seems that the Stream is loaded before loading concern, make sure that you have applied the concerns inside the class definition. When rails loader matches class name for Stream constant, it autoloads it before the finishing evaliation of the faculty_block, so replace constants in it with symbols:
[:Program, :Stream, :Course, :Department, :Teacher].each do |sym|
model = sym.to_s.constantize
model.send(:include, FacultyBlock)
model.send(:extend, FacultyBlock::ClassMethods) # I added this just to try
end

Undefined method m when using SimpleDelegator in Rails 4

I was barking up the wrong tree with my original answer - I still have the problem but the plot thickens
I'm upgrading a Ruby 1.8.7/ Rails 3.0.20 project to Ruby 2.1.2 /Rails 4.1.8
In the code I have a class which delegates a number of instance methods.
class Account < ActiveRecord::Base
has_one :subscription
delegate :trial?, :payg? :to => :subscription
end
I have a decorator
class AccountOverview < SimpleDelegator
def self.for(account)
new(account)
end
def description
if payg?
'Pay As You Go'
elsif trial?
'Free Trial'
else
'Subscription'
end
end
end
Accessing the decorator from view gives the error message:
ActionView::Template::Error (undefined local variable or method `m' for ):
I hunted for an extraneous m, but can't find one.
I had thought that it was using the decorator ok for methods that didn't include delegated methods and that by defining the delegated functions within the class stopped the error:
def payg?
subscription.payg?
end
def trial?
subscription.trial?
end
However, it was not the case. What I was seeing was that a second attempt to render the view succeeds. But if I restart the server I get the error again.
I've tried the approach of instantiating SimpleDelegator as suggested, rather than deriving from it, and found that I could not access the methods in the original class.
Try this in the rails console:
class Test1
def testing
puts 'hi'
end
end
class Test2
def initialize(test)
SimpleDelegator.new(test)
end
def testing2
puts 'hello'
end
end
t = Test1.new
t.testing
hi
=> nil
h = SimpleDelegator.new(t)
h.testing
hi
=> nil
h = Test2.new(t)
h.testing
NoMethodError: undefined method `testing' for #<Test2:0x007fbea15d27a0>
But if instead I use
2.1.2 :008 > class Test2 < SimpleDelegator
2.1.2 :009?> def testing2
2.1.2 :010?> puts 'hello'
2.1.2 :011?> end
2.1.2 :012?> end
=> :testing2
2.1.2 :013 > h = Test2.new(t)
=> #<Test1:0x007fee090afc90>
2.1.2 :014 > h.testing
hi
=> nil
2.1.2 :015 > h.testing2
hello
=> nil
Also, I have found that the code that fails rendering in the view works in the console ( deriving from SimpleDelegator ):
a = Account.last
c = AccountOverview.new(a)
c.description
=> "Free Trial"
Reduced the classes to the very simplest
class AccountOverview < SimpleDelegator
def self.for(account)
new(account)
end
def description
'Pay As You Go'
end
class Account < ActiveRecord::Base
end
Still seeing the same error referring to missing method m
Created a brand new rails 4 project and added the same code and ran against the same db - this worked with no errors, so its something in my legacy setup.
Have given up and removed SimpleDelegator from the code and just used delegate to map the required functions to an instance variable for the base object and its now working. But not very satisfying.
class AccountOverview
delegate :payg?, :trial? :to => :#account
def initialize(account)
#account = account
end
def description
if payg?
'Pay As You Go'
elsif trial?
'Free Trial'
else
'Subscription'
end
end
end

module attr_accessor from another module

In Ruby, what's the correct way for a 'child' module to inherit attributes from a 'parent' module? It seems that if you define an attribute in one module and then extend that module and mixin the child module to a class, I should be able to access the attribute from the child module, but not having any luck...
module A
attr_accessor :foo
end
module B
extend A
def not_worky
p "#{foo}"
end
end
class C
include B
end
class D
include A
end
irb(main):027:0* d = D.new
irb(main):028:0> d.foo=> nil
irb(main):033:0* c = C.new
irb(main):034:0> c.foo
NoMethodError: undefined method `foo' for #<C:0x553853eb>
irb(main):038:0> c.not_worky
NameError: undefined local variable or method `foo' for #<C:0x553853eb>
This was due to my own mis-understanding of what I was trying to do. Works as expected if I simply use the standard include mechanism. A more realistic example...
module App
attr_accessor :log
def initialize
self.log = 'meh'
end
end
module DB
include App
def go
p log
end
end
class Foo
include DB
end
irb(main):002:0> f = Foo.new
=> #<Foo:0x7cece08c #log="meh">
irb(main):003:0> f.go
"meh"
include is for adding instance methods and extends is for adding class methods. So you could do like this
B.foo #=> nil
read more here and here

What are delegates in ruby?

I've been browsing the source code for rails, and find a number of mentions to "delegate"
What does this do and how does this work?
here is the official explanation:
delegate(*methods) public
Provides a delegate class method to easily expose contained objects’ public methods as your own.
class Greeter < ActiveRecord::Base
def hello
'hello'
end
def goodbye
'goodbye'
end
end
class Foo < ActiveRecord::Base
belongs_to :greeter
delegate :hello, to: :greeter
end
Foo.new.hello # => "hello"
Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
here's some other explanations of how it works with examples:
http://brettu.com/rails-daily-ruby-tip-20-use-the-delegate-method-in-rails-to-reduce-code/
http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate/
http://pivotallabs.com/rails-delegates-are-even-more-useful-than-i-knew/
Delegates help you stay within the LoD without braking the SRP.
http://en.wikipedia.org/wiki/Law_of_Demeter

In Rails 3.1, why does my custom validator raise 'NameError: uninitialized constant' when another model is called?

In a Rails 3.1 project, I have a model class with a custom validator:
class Car < ActiveRecord::Base
validate :road_must_exist_nearby, :on => :create
# ...
def not_a_validator_method
Road.exists_nearby?
end
def road_must_exist_nearby
if !Road.exists_nearby?
# ...
end
end
end
When I attempt to save my instance of Car ...
> car = Car.new
> car.save
I get the following error:
NameError: uninitialized constant Car::Road
Why does calling Road.exists_nearby? from a normal instance method work?:
> car.not_a_validator_method
=> true
And why does calling it from a validator method raise an error, as though Rails believes Road should be called through Car?:
> car.road_must_exist_nearby
NameError: uninitialized constant Car::Road
And how can I make the validator method work?
I'm only guessing, but I'd say it's a namespace/scope issue. Rails is interpreting the "Road" constant as existing in the scope of Car (ie Car::Road). You can probably get around it by referencing the global namespace using: "::Road"

Resources