ArgumentError : Missing Keyword when Init a Class - ruby-on-rails

I have a simple pattern result class to init on controller, everything works well on ruby 2.3.x <= 2.7.x, I try on ruby 3.0.1 with Rails 6.1.4.
My project structure looks like :
app/
..controllers
....api
......v1
.........files_controllers.rb
..jobs
..mailers
..serializers
..services
....v1
......list_result.rb
..value_objects
A simple pattern result class I put on services directory
module V1
class ListResult
attr_reader :status,
:status_message,
:data,
:meta
SUCCESS = 1
def initialize(status_message:, data:, meta:)
#status = SUCCESS
#status_message = status_message
#data = data
#meta = meta
end
def success?
#status == SUCCESS
end
end
end
And try to in on controller looks like :
V1::ListResult.new(status_message: "", data: [], meta: {})
I'm getting this error :
ArgumentError: wrong number of arguments (given 1, expected 0; required keywords: status_message, data, meta)
from /app/services/v1/list_result.rb:10:in `initialize
but it's works on rails console
3.0.1 :001 > V1::ListResult.new(status_message: "", data: [], meta: {})
=> #<V1::ListResult:0x00007f8d3dbaa730 #data=[], #meta={}, #status=1, #status_message="">
irb console
3.0.1 :001 > class MyClass
3.0.1 :002 > def initialize(status_message:, data:, meta:)
3.0.1 :003 > puts "#{status_message} #{data} #{meta}"
3.0.1 :004 > end
3.0.1 :005 > end
3.0.1 :006 > MyClass.new(status_message: "", data: [], meta: {})
[] {}
I've read about Separation of positional and keyword arguments in Ruby 3.0, but I confused why it's work on rails console and irb console only?

Related

Graphiti can not call method with args including keyword inside attribute/extra_attribute

my environment:
Ruby 3.1.3
Rails 7.0.4
Graphiti 1.3.9
Graphiti-rails 0.4.0
I faced this issue
extra_attribute :attribute_name, :array do
get_my_age(#object, date: Date.current)
end
def get_my_age(birth, date:)
end
it will throw ArgumentError (wrong number of arguments (given 2, expected 1; required keyword: date)):
but, if I try with
extra_attribute :attribute_name, :array do
wrapper(#object, Date.current)
end
def wrapper(a, b)
get_my_age(a, date: b)
end
def get_my_age(birth, date:)
end
it will not throw any errors.
Which am I wrong? or is this a bug of graphiti?

Why does subclassing ActiveSupport::TimeZone break its class-level [] operator?

With some trepidation, I decided to subclass ActiveSupport::TimeZone, but I can't get very far because when I call [] on my subclass it fails to invoke the superclass's [] method. I thought it might have had something to with the fact that the operator overload happens in a class method, so I tried this:
Loading development environment (Rails 4.2.1)
2.2.1 :001 > class Foo; def Foo.[](f); f; end; end
=> :[]
2.2.1 :002 > Foo['baz']
=> "baz"
2.2.1 :003 > class Bar < Foo; end
=> nil
2.2.1 :004 > Bar['baz']
=> "baz"
So that worked exactly as I thought it would. But if that works, why does this fail?
2.2.1 :005 > ActiveSupport::TimeZone["America/New_York"]
=> #<ActiveSupport::TimeZone:0x007f80835c18a8 #name="America/New_York", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: America/New_York>, #current_period=#<TZInfo::TimezonePeriod: #<TZInfo::TimezoneTransitionDefinition: #<TZInfo::TimeOrDateTime: 1425798000>,#<TZInfo::TimezoneOffset: -18000,3600,EDT>>,#<TZInfo::TimezoneTransitionDefinition: #<TZInfo::TimeOrDateTime: 1446357600>,#<TZInfo::TimezoneOffset: -18000,0,EST>>>>
2.2.1 :006 > class T < ActiveSupport::TimeZone; end
=> nil
2.2.1 :007 > T["America/New_York"]
NoMethodError: undefined method `[]' for nil:NilClass
The method relies on calling [] on an #lazy_zones_map instance variable, which your subclass does not have.
Edit: an example of the behavior:
class Foo
#foo = []
def self.[](arg)
#foo[arg]
end
end
class Bar < Foo
end
Foo[0] #=> nil
Bar[0] #=> undefined method `[]` for nil:NilClass

Big Decimal Stored as 60.00, Returns as 0.0?

I am customizing a Spree 2.3 application in Rails 4. When I save a price.amount, it appears to save correctly in the database, but when I retrieve it, it is wrapped in the BigDecimal class and returns 0.
How can I store, or retrieve, the correct value?
# in the form
<%= number_field_tag :amount %>
# controller action
#variant.price = params[:amount]
# appears in PostgresQL database as type 'numeric'
id: 35, amount: 60.00
# retrieved in Rails console as BigDecimal class instance
# looks like the wrong amount
2.1.1 :001 > Spree::Price.find_by_id(35).amount
=> #<BigDecimal:105806d20,'0.0',9(27)>
# converts to 0.0
2.1.1 :002 > Spree::Price.find_by_id(35).amount.to_f
=> 0.0
# testing data retrieval in the console
2.1.1 :003 > ActiveRecord::Base.connection.execute("SELECT * FROM spree_prices WHERE id=35").first
=> {"id"=>"35", "variant_id"=>"35", "amount"=>"60.00", "currency"=>"USD", "deleted_at"=>nil}
2.1.1 :004 > Spree::Price.find(35)
=> #<Spree::Price id: 35, variant_id: 35, amount: #<BigDecimal:109ec4a28,'0.0',9(27)>, currency: "USD", deleted_at: nil>
The problem was in a typo in the price model decorator. The pure PostgresQL doesn't trigger the callback, but using the 'find' method does. This accounts for the seemingly impossible results above.
#original price_decorator.rb
after_initialize :set_defaults
def set_defaults
self.amount = 0.0
end
#corrected price_decorator.rb
after_initialize :set_defaults
def set_defaults
self.amount ||= 0.0
end

protection level for model attributes in rails

Suppose the following situation
class User < ActiveRecord::Base
private
def password= p
self[:password] = p
end
def password
self[:password]
end
end
If anyone with access to the Rails console can do:
Loading development environment (Rails 4.0.0)
2.0.0p247 :001 > User
=> User(id: integer, name:string, password:string)
2.0.0p247 :002 > u = User.find(1)
=> #<User id: 1, name: "Jack", password: "da6c253ffe0975ca1ddd92865ff3d5f0">
2.0.0p247 :003 > u.password = "123"
NoMethodError: private method 'password' called for #<User:0xa9145b0>
2.0.0p247 :004 > u[:password] = "123"
=> "123"
2.0.0p247 :005 > u
=> #<User id: 1, name: "Jack", password: "123">
2.0.0p247 :005 > u.save
=> true
Why does this happen? How can I encapsulate critical fields?
I am guessing that password is attr_accessible in the model. When a field is attr_accessible, Rails automatically lets you read and write to the field. You have a private password method that overwrites the Rails password and password= methods, but you did not overwrite the [] and []= methods as well. You can either overwrite the [] and []= methods or make it so password is not attr_accessible.
Here is a code example of how to overwrite the [] method:
class User < ActiveRecord::Base
def [](word)
puts "I am the master of: #{word}"
end
def []=(key, value)
puts "Fluffy monsters"
end
end
With this revised code, here is what the [] method will return:
>> u[:password] = "123"
=> nil
# prints "Fluffy monsters" in the console
>> u[:password]
=> nil
# prints "I am the master of: password" in the console

opening Array in ruby on rails console v. irb

I wish to make my code a little more readable by calling #rando on any array and retrieve a random element (rando because a rand() method already exists and I don't want there to be any confusion).
So I opened up the class and wrote a method:
class Array
def rando
self[ rand(length) ]
end
end
This seems far too straightforward.
When I open up irb, and type arr = %w(hi bye) and then arr.rando I get either hi or bye back. That's expected. However, in my rails console, when I do the same thing, I get ArgumentError: wrong number of arguments (1 for 0)
I've been tracing Array up the rails chain and can't figure it out. Any idea?
FWIW, I'm using rails 2.3.11 and ruby 1.8.7
Works fine in my case :
Loading development environment (Rails 3.0.3)
ruby-1.9.2-p180 :001 > class Array
ruby-1.9.2-p180 :002?> def rando
ruby-1.9.2-p180 :003?> self[ rand(length) ]
ruby-1.9.2-p180 :004?> end
ruby-1.9.2-p180 :005?> end
=> nil
ruby-1.9.2-p180 :006 > arr = %w(hi bye)
=> ["hi", "bye"]
ruby-1.9.2-p180 :007 > arr.rando
=> "bye"

Resources