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?

2

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

This post illustrates this also and gives an example of using * and flatten to create the hash.
@Caley_Woods That's a great post! I will 'steal' the * + flatten Technic.
@Harry I'd hit up the maintainer on Github and let them know you have to use a workaround with RUBY_VERSION < 1.9. It looks like you're using RVM, I might go as far as flipping RVM to 1.9.2 and seeing if NeX's example still works in 1.9.2. If it does I'd consider a pull request since the new code works with multiple rubies.
0

This looks like it's trying to do a merge on an Array which is not a method the Array class in Ruby. Merge is supported for Hash, it looks like your returned object is not the correct type. The author was definitely relying on a hash, in the next to last line 'with_indifferent_access' is called which is trying to allow you to select items from the hash with strings or symbols.

I can't examine the gem further right now and I wish I could provide a more helpful answer. If this hasn't been answered later i'll come back and help you out.

Not sure why the author is using double and single quotes in options and vars. He's also trying to populate the hash by hand instead of with inject. It's not awful by any means but I think there's room for improvement in the small bit of code you posted from the file.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.