Cannot override/monkey patch a rails method with rails 3.1.3 - ruby-on-rails

I am trying to override an active resource method like explained in this question : Remove .xml extension from ActiveResource request and this one :
i want to use a REST api, i cannot manage to set active resource to use it
To do so i tested :
Creating in the /config/in itializers/ folder of my app a file named active_resource.rb with the following code :
class ActiveResource::Base
def element_path(id, prefix_options = {},query_options = nil)
check_prefix_options(prefix_options)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
end
end
Adding the method inside my model. Here is my model code :
class Player < ActiveResource::Base
def element_path(id, prefix_options = {}, query_options = nil)
check_prefix_options(prefix_options)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
end
self.site = "http://ws.maniaplanet.com/"
self.user="**********"
self.password="*********"
end
To validate the overriding of my custom code I have tried to use
puts "called this method"
or
ActionController::Base.logger.info "called this method"
It has never worked.
Why can't i override the rails method element path ?
UPDATE
Tried to put active_resource.rb in extra after uncommenting the config.autoload_paths += %W(#{config.root}/extras) line in application.rb. No change
If i put the base.rb file with my class and method in lib/active_resource/ it breaks my app. I cannot launch rails server anymore

You should override class method, not instance one, so:
class Player < ActiveResource::Base
def self.element_path(id, prefix_options = {}, query_options = nil)
#...
end
end
That would be enough, if you going to make requests only from Player model.
If you want this behaviour for any model, you should monkey patch ActiveResource::Base, again, the class method.
# config/initializers/active_resource_patch.rb
class ActiveResource::Base
def self.element_path(id, prefix_options = {}, query_options = nil)
#...
end
end

Related

Extending ActiveModel::Serializer with custom attributes method

I am trying to create my own attributes method called secure_attributes where I pass it an array of attributes and the minimum level the authorized user needs to be to view those attributes. I pass the current level of the authorized user as an instance_option. I'd like to extend the Serializer class so I can use this method in multiple serializers, but Im having issues.
This is what i have so far:
in config/initializers/secure_attributes.rb
module ActiveModel
class Serializer
def self.secure_attributes(attributes={}, minimum_level)
attributes.delete_if {|attr| attr == :attribute_name } unless has_access?(minimum_level)
attributes.each_with_object({}) do |name, hash|
unless self.class._fragmented
hash[name] = send(name)
else
hash[name] = self.class._fragmented.public_send(name)
end
end
end
end
end
and then in the individual serializer I have things like this:
secure_attributes([:id, :name, :password_hint], :guest)
and then
def has_access?(minimum_level=nil)
return false unless minimum_level
return true # based on a bunch of logic...
end
But obviously secure_attributes cannot see the has_access? method and if I put has_access inside the Serializer class, it cannot access the instance_options.
Any idea how I can accomplish what I need?
Maybe you want to do following - but I still do not get your real purpose, since you never did anything with the attributes but calling them:
module ActiveRecord
class JoshsSerializer < Serializer
class << self
def secure_attributes(attributes={}, minimum_level)
#secure_attributes = attributes
#minimum_level = minimum_level
end
attr_reader :minimum_level, :secure_attributes
end
def initialize(attr, options)
super attr, options
secure_attributes = self.class.secure_attributes.dup
secure_attributes.delete :attribute_name unless has_access?(self.class.minimum_level)
secure_attributes.each_with_object({}) do |name, hash|
if self.class._fragmented
hash[name] = self.class._fragmented.public_send(name)
else
hash[name] = send(name)
end
end
def has_access?(minimum_level=nil)
return false unless minimum_level
return true # based on a bunch of logic...
end
end
end

Access varible in ruby after initialize

I am trying to access variable in ruby after initialize, but i didn't get that variable , anything wrong in that?
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
Test.new(params)
#can i get that two instance variable
end
end
You should probably set up attribute accessors, then use them this way:
class Test
attr_accessor :has_test
attr_accessor :limit_test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def self.method1(params)
t = Test.new(params)
// can i get that two instance variable
// Yes:
// use t.has_test and t.limit_test
end
end
You are mixing an instance and a class method in your example.
If this is really what you want, then you have to define an accessor with attr_reader:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
attr_reader :has_test
attr_reader :limit_test
def self.method1(params)
obj = Test.new(params)
p obj.has_test
p obj.limit_test
end
end
Test.method1(has_test: 1, limit_test: 3)
It the instance/class-method is a mistake, then this example may help you:
class Test
def initialize(params)
#has_test = params[:has_test]
#limit_test = params[:limit_test]
end
def method1()
p #has_test
p #limit_test
end
end
obj = Test.new(has_test: 1, limit_test: 3)
obj.method1
If you define also the accessors like in the first code, then you have again access from outside the class.
Just in case you don't want a reader, see also Access instance variable from outside the class

ruby on rails accessing custom class attributes from its object

I have a custom class in my application controller. Like below:
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
end
class Data
def initialize
#data_1 = nil
end
end
Now in my controller method i have created an object of type Defaults
def updateDefaultValues
defaults = Defaults.new
# i am unable to update the value, it says undefined method
defaults.value_2 = Table.maximum("price")
defaults.data.data_1 = defaults.value_2 * 0.3
end
How to access value_2 from defaults object?
defaults.value_2
Also, how to access data_1 attribute from data object within defaults object?
defaults.data.data_1
You should use attr_accessor:
class Defaults
attr_accessor :value_1, :value_2, :data
# ...
end
defaults = Defaults.new
defaults.value_1 = 1
# => 1
defaults.value_1
# => 1
As you are using def as a keyword to define the method, that means def is a reserved keyword. You can't use reserved keywords as a variable.
You just need to rename your variable name from def to something_else and it should work! Your code will look like this:
def updateDefaultValues
obj = Defaults.new
obj.value_2 = Table.maximum("price")
obj.data.data_1
end
EDIT:
As per OP's comment & updated question, he had used def just as an example, here is the updated answer:
You may need attr_accessor to make attrs accessible:
class Defaults
attr_accessor :value_1, :value_2, :data
...
...
end
class Data
attr_accessor :data_1
...
...
end
Add value_2 method in Defaults class
class Defaults
def initialize
#value_1 = "1234"
#value_2 = nil
#data = Data.new
end
def value_2
#value_2
end
end
class Data
def initialize
#data_1 = nil
end
end

Active resource complaining about expects an hash

I am using active resource to get data from an api and display it,
My controller model.rb has
class Thr::Vol::Dom < ActiveResource::Base
class << self
def element_path(id, prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}"
end
def collection_path(prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
end
end
ActiveResource::Base.site = 'http://10.00.0.00:8888/'
self.format = :json
self.collection_name= "/vv/test/domains"
def self.find
x = superclass.find(:one, :from => '/vv/test/domains/2013-06-25T05:03Z')
x
end
end
When i call this Thr::Vol::Dom.find method it returns the following error:
ArgumentError: expected an attributes Hash,
got ["0.0.0.0", "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4"]
The api is expected to feed something like this
{"abs.com":["0.0.0.0", "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4"]}
for the call i made.
The API returns the correct hash but i guess active resource is not able to read it properly, it is directly reading the value in the key-value pair of the hash.
I want to fix this "ArgumentError" error , i want to display the contents of the returned hash in the view.
You can change how ActiveResource handle json response with
class YourModel < ActiveResource::Base
self.format = ::JsonFormatter.new(:collection_name)
end
In lib/json_formatter.rb
class JsonFormatter
include ActiveResource::Formats::JsonFormat
attr_reader :collection_name
def initialize(collection_name)
#collection_name = collection_name.to_s
end
def decode(json)
remove_root(ActiveSupport::JSON.decode(json))
end
private
def remove_root(data)
if data.is_a?(Hash) && data[collection_name]
data[collection_name]
else
data
end
end
end
If you pass self.format = ::JsonFormatter.new(:categories) it will find and remove categories root element in your json returned by your API.
The API is returning a JSON object, not a Ruby hash. You'll need to convert it into a hash by using Ruby's JSON module:
require 'JSON'
hash = JSON.parse('{"abs.com":["0.0.0.0", "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4"]}')
This will return a hash and then you'll notice that the key/value pair will work as expected:
hash["abs.com"] => ["0.0.0.0", "1.1.1.1", "2.2.2.2", "3.3.3.3", "4.4.4.4"]

Creating a class method with Ruby problems

Why does the following code result in the error 'undefined local variable or method `foo_client' for Foo::People:Class'
class Foo::People
class << self
def get_account_balance(account_num)
foo_client.request :get_account_balance, :body => {"AccountNum" => account_num}
end
end
def foo_client
##client ||= Savon::Client.new do|wsdl, http|
wsdl.document = PEOPLE_SERVICE_ENDPOINT[:uri] + "?WSDL"
wsdl.endpoint = PEOPLE_SERVICE_ENDPOINT[:uri]
end
end
end
def get_account_balance is inside the class << self block, so it's a class method. def foo_client is not, so it's an instance method. So you can't call foo_client from get_account_balance because you're not calling it on an instance of People.

Resources