How does `new` create an object? - ruby-on-rails

In Rails initializers, I found the following line:
LineAdsClient = LineAds::AdsClient.new(api_key: LineAccessToken.order('created_at').last[:access_token])
I tried to look for AdsClient class in the workspace, but I could not find it.
How does this style of object creation work without declaring a class?
After creating an instance, we are using LineAdsClient like below:
def client
#client ||= ::LineAdsClient
end

If you couldn't find the class, it doesn't mean there's no class. You just didn't find it (looked in the wrong place or other reasons).
If you're using Pry, try this in your rails console
show-source LineAds::AdsClient
# or
show-source LineAds::AdsClient.new
It'll show you where it is defined.

Related

How to use cattr_accessor to define config in a Rails initializer

Given the following class (this is the actual class there is no other code)
class PageRepo
cattr_accessor :root_path
end
and initializer file
PageRepo.root_path = Rails.root.join("content")
When I run
rails console
PageRepo.root_path
=> PageRepo.root_path
=> #<Pathname:/Users/blah/my_rails_app/content/pages>
However when I try to access this in my rails controller the root_path value is nil. (I've inspected this with web_console.)
No other class subclasses or is a parent of the PageRepo class and I'm not setting the root_path to nil anywhere at class level or instance level after the initializer stage. I have restarted spring and my server multiple times to no avail.
Is there something I'm not aware of when it comes to either Rails initializers or cattr_accessor?
Update
I'd like to set the path like this because throughout my code I will be initialising a PageRepo instance and the path will not change. However, it may change across different environments. I.e. in development it the path will be different than that of the test and production environments. Whilst I could just do
def initialize
#root_path = ENV['ROOT_PATH']
end
I'd prefer to not force the programmer to use ENV VARS to do this and hence my attempt above.
My solution would be just using a class method
class PageRepo
self.root_path
Rails.root.join("content")
end
end
PageRepo.root_path would return #<Pathname:/Users/blah/my_rails_app/content/pages>.
You want to have #<Pathname:/Users/blah/my_rails_app/content/pages>? or this depends on the action?
I believe your initializer is not working
an interesting post, what you are trying to achieve is writing something like this in the class initializer or constructor
class PageRepo
self.initialize
self.root_path = Rails.root.join("content")
end
end
but I never saw self.initialize being used with rails. so I believe the first approach is better.

Override method Ruby

I would like to override the method: authorize_endpoint_url from the Gem in a Rails application: https://github.com/AzureAD/omniauth-azure-activedirectory/blob/master/lib/omniauth/strategies/azure_activedirectory.rb
I tried to do it by adding a file to config/initializers/oauth.rb
With the code:
module OmniAuth
module Strategies
# A strategy for authentication against Azure Active Directory.
class AzureActiveDirectory
def request_phase
debugger
"www.hans.com"
end
end
end
end
But this approach doesn't seem to work, nothing get's actually overwriten. What do I wrong? Thank you
When writing "monkey patch" style alterations you'll want to ensure they're loaded correctly. One way to test this is, after all is said and done, to interrogate Ruby to find out which method is actually being used:
OmniAuth::Strategies::AzureActiveDirectory.instance_method(:‌​request_phase).sourc‌​e_location
The instance_method call returns an object with information about that method and the source_location property tells you where that was defined.
If if's your method, great, you got it loaded right. If not you may need to check that you're hooking in at the correct time.

Ruby overriding method from Trie gem - undefined method

I use Trie (https://github.com/tyler/trie) gem in project and love it. But it has one issue that is really anoying.
has_key? method returns nil when key is not found instead of false (as every method ending with ? should)
I've tried opening an issue on their GitHub (https://github.com/tyler/trie/issues/26) but no luck.
So, reasonable next step - try to override the method.
I added this to my project:
class Trie
alias :old_has_key? :has_key?
def has_key?(key)
puts "My new Trie has_key"
old_has_key?(key)
end
end
Just to see if I can get away with it.
Unfortunately, when I run rails console I get:
`<class:Trie>': undefined method `has_key?' for class `Trie' (NameError)
As I found elsewhere, this should work. Any idea why it doesn't?
What I'm missing here? Location of trie.rb? Something else?
From your error message, it seems you are calling the has_key? method on the Trie class, not an instance of it. If you create an instance, your code works just fine:
my_trie = Trie.new
my_trie.has_key?('foo')
# My new Trie has_key
# => nil
So I found the problem.
My new class was nested under /lib folder in my Rails app. As soon as I moved it to /lib/utils/ it worked!
This means that loader picked up my custom class before actual Trie class. Still not sure why.
You can patch a little more simply:
class Trie
def has_key?(key)
!!super
end
end

Uninitialized constant trying to reopen a Class

I am using a plugin in Rails, and I call its methods without problems:
plugin_module::class_inside_module.method_a(...)
I want to re-open the class_inside_module and add a new method, I tried in many different ways. I can't figure out why in this way doesn't work:
class plugin_module::class_inside_module
def new_method
puts 'new method'
end
end
I get the error: uninitialized constant plugin_module, but how is possible if I can call without problem plugin_module::class_inside_module.any_methods ?
Do you know why I get that error ? why "uninitialized constant" ? (it is a class declaration :-O )
Do you have any ideas how I can add a new methods in a class inside a module (that is part of a plugin) ?
Thank you,
Alessandro
If you have written your class and module-names like you did, so plugin_module instead of PluginModule this is against ruby/rails standards, and rails will not be able to automatically find the class and module.
If you write something like
module MyModule
class MyClass
end
end
Rails will expect this file to be located in lib\my_module\my_class.
But this can always easily be overwritten by explicitly doing a require.
So in your case, when you write
module plugin_module::class_inside_module
Rails will not know where to find the module plugin_module.
This way of writing only works if module plugin_module is previously defined (and loaded).
So either add the correct require, or rename your modules to standard rails naming, or write it as follows:
module plugin_module
class class_inside_module
This way will also work, because now the order no longer matters.
If the module is not known yet, this will define the module as well.
Either you are re-opening the class, or you define it first (and the actual definition will actually reopen it).
Hope this helps.
Have you tried reopening the module that's wrapping the class, rather than relying on ::?
module plugin_module
class class_inside_module
def new_method
puts 'new_method'
end
end
end
By the way, you know that the proper name for modules and classes is use CamelCase with a capital first letter?
module PluginModule
class ClassInsideModule
def new_method
puts 'new_method'
end
end
end

Finding out where methods are defined in Ruby/Rails (as opposed to Java)

I am just getting started with Ruby on Rails. Coming from the Java world, one thing that I am wondering is how do Ruby/Rails developers find out where methods are actually defined.
I am used to just clicking on the method in Eclipse to find where is is defined even in third party libraries (supposing I have the source code).
A concrete example: I am trying to find out how the Authlogic gem apparently changes the constructor of my User class to require an additional parameter (called :password_confirmation) even though the User class doesn't even inherit from anything related to Authlogic.
Probably I am just overlooking something really obvious here (or maybe I still can't wrap my head around the whole "convention over configuration" thing ;-))
It's slightly difficult to quickly find the method location for dynamic languages like Ruby.
You can use object.methods or object.instance_methods to quickly find out the methods.
If you are using Ruby 1.9, you can do something like this:
object.method(:method_name).source_location
For more information on source_location - click here
The Pry gem is designed precisely for this kind of explorative use-case.
Pry is an interactive shell that lets you navigate your way around a program's source-code using shell-like commands such as cd and ls.
You can pull the documentation for any method you encounter and even view the source code, including the native C code in some cases (with the pry-doc plugin). You can even jump directly to the file/line where a particular method is defined with the edit-method command. The show-method and show-doc commands also display the precise location of the method they're acting on.
Watch the railscast screencast for more information.
Here are some examples below:
pry(main)> show-doc OpenStruct#initialize
From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb # line 46:
Number of lines: 11
visibility: private
signature: initialize(hash=?)
Create a new OpenStruct object. The optional hash, if given, will
generate attributes and values. For example.
require 'ostruct'
hash = { "country" => "Australia", :population => 20_000_000 }
data = OpenStruct.new(hash)
p data # -> <OpenStruct country="Australia" population=20000000>
By default, the resulting OpenStruct object will have no attributes.
pry(main)>
You can also look up sourcecode with the show-method command:
pry(main)> show-method OpenStruct#initialize
From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb # line 46:
Number of lines: 9
def initialize(hash=nil)
#table = {}
if hash
for k,v in hash
#table[k.to_sym] = v
new_ostruct_member(k)
end
end
end
pry(main)>
See http://pry.github.com for more information :)
None of people advising Pry gem mentionned the method called find-method, which is probably what author was looking for.
Here's the example:
pry(main)> find-method current_user
Devise::Controllers::Helpers
Devise::Controllers::Helpers#current_user
WebsocketRails::ConnectionAdapters::Base
WebsocketRails::ConnectionAdapters::Base#current_user_responds_to?
Then, you can browse the method code by following #banister's tips.
You could use something like pry. See its railscast also.
There are several ways to change an existing class. E.g. if you want to modify the String class write:
class String
def my_custom_method
puts "hello!"
end
end
But there are other options like mixing in modules or adding/modifying methods by using meta-programming.
Anyhow, having some object you can always:
puts obj.methods.inspect
Either do it in your code or use the debugger.
The other option is to read the code. In particular you should read the gem's unit tests (./spec, ...). There are quite a lot of authors stating that unit tests make documentation obsolete.
In Ruby you can also add both class and instance methods to a given class by using mixins.
Essentially if you have a module you can add its methods to a given class using both include and extend class methods. A brief example on how those works is the following
Module A
def foo
"foo"
end
end
Module B
def bar
"bar"
end
end
Class YourClass
include A
extend B
end
p YourClass.new.foo # gives "foo" because the foo method is added as instance method
p YourClass.bar # gives "baz" because the bar method is added as class method
Because Ruby is a dynamic language, these statements can be used everywhere. So to come to your question there is no need to extend an authlogic class to get its methods. Many plugins uses this instruction when loaded
ActiveRecord::Base.send :include, ModuleName
In this way they tell to every AR object to include some plugin defined module and you get all the methods in AR objects.
Another technique used by many acts_as plugins is to include their modules only when the acts_as call is used in the base class.
Other useful references
What is the difference between include and extend in Ruby?
A quick tutorial about mixins

Resources