Ruby – rails-settings: NoMethodError: undefined method `merge’ for []:Array

rubyruby-on-rails-3

I'm trying to implement the rails-settings gem (https://github.com/100hz/rails-settings) into my Rails 3 project using Ruby 1.8.7

Setting and retrieving the settings works perfectly, but I get an error if I try getting all settings of a specific user.

So, in the 'rails console' the following works:

user = User.find(123)
user.settings.color = :red
user.settings.color

But if I try to get all settings:

user.settings.all

I get:

NoMethodError: undefined method `merge' for []:Array

from /[…]/.rvm/gems/ruby-1.8.7-p334/bundler/gems/rails-settings-883114dfd933/lib/rails-settings/settings.rb:55:in `all'

from (irb):5

line 55 in the settings.rb:

#retrieve all settings as a hash (optionally starting with a given namespace)
def self.all(starting_with=nil)
  options = starting_with ? { :conditions => "var LIKE '#{starting_with}%'"} : {}
  vars = thing_scoped.find(:all, {:select => 'var, value'}.merge(options))

  result = {}
  vars.each do |record|
    result[record.var] = record.value
  end
  # line 55 is below this one...
  @@defaults.select{ |k| k =~ /^#{starting_with}/ }.merge(result).with_indifferent_access
end

Whats the problem here? Or is this a ruby 1.8.7 vs. 1.9.2 thing?

Best Answer

That's a Ruby 1.8.7 vs. 1.9.2 thing

The Hash select method under ruby 1.8.7 will return an Array of Arrays.

Example:

{:a => 'a', :b => 'b', :c => 'c'}.select {|k, v| v > 'a'} #=> [[:b,'b'],[:c,'c']]

While the same thing running Ruby 1.9.2 will return:

{:a => 'a', :b => 'b', :c => 'c'}.select {|k, v| v > 'a'} #=> {:b => 'b',:c => 'c'}

You will need to post process the result and turn it into a hsah again or use something like inject.

Edit:

Here is a quick/ugly example of the inject

{:a => 'a', :b => 'b', :c => 'c'}.inject({}) {|r, e| e[1] > 'a' ? r.merge({e[0] => e[1]}) : r }

Semantically speaking:

collection.inject(container) { |container, element| select_condition ? container + element : container }

Edit 2: (Based on @CaleyWoods post)

Hash[*@@defaults.select{ |k,v| k =~ /^#{starting_with}/ }.flatten].merge(result)

The |k, v| will prevent unnecessary warnings.

Related Topic