volt
volt

Reputation: 357

Select specific attributes

#<Example example_id: 13, example2_id: 81, year: 2000, january: 12, february: 3, march: 3, april: 4, may: 5, june: 2, july: 4, august: 24, september: 4, october: 24, november: 4, december: 4>

I want to put the values of months in a array like this:

array_example = [12, 3, 3, 4, 5, 2, 4, 24, 4, 24, 4, 4]

I know I can do this (example below) but I want a better way.

   example.attributes.each do |attr_name, attr_value|
      if attr_name == "january" || attr_name == "february" || attr_name == "march" ||
         attr_name == "april" || attr_name == "may" || attr_name == "june" ||
         attr_name == "july" || attr_name == "august" || attr_name == "september" ||
         attr_name == "october" || attr_name == "november" || attr_name == "december"
                    @array_example << attr_value
      end
    end

Upvotes: 0

Views: 1081

Answers (4)

Jordan Running
Jordan Running

Reputation: 106027

Hash#values_at is for exactly this:

example.attributes.values_at(:january, :february, :march, :april, :may, :june, :july, :august, :september, :october, :november, :december)
# => [12, 3, 3, 4, 5, 2, 4, 24, 4, 24, 4, 4]

It's probably best to put the month names in a constant (e.g. in your Example model), if only for readability, e.g.:

MONTH_ATTRS = %i[ january   february  march     april
                  may       june      july      august
                  september october   november  december ]
# Or...
MONTH_ATTRS = Date::MONTHNAMES.drop(1).map {|m| m.downcase.to_sym }

(The latter uses Ruby's built-in Date::MONTHNAMES constant; drop(1) is necessary because Date::MONTHNAMES[0] is nil, presumably so January will be at index 1.)

Then:

example.attributes.values_at(*Example::MONTH_ATTRS)

P.S. If you would rather have a hash than an array, you can use Hash#slice from ActiveSupport:

example.attributes.slice(*Example::MONTH_ATTRS)
# => { :january => 12,  :february => 3, :march => 3,    :april => 4,
#      :may => 5,       :june => 2,     :july => 4,     :august => 24,
#      :september => 4, :october => 24, :november => 4, :december => 4 }

P.P.S. If you're not using the model object for anything else—i.e. you just want the month values and nothing else, you should use ActiveRecord::Calculations#pluck in your query, e.g.:

Example.where(...).pluck(*Example::MONTH_ATTRS)

pluck tells ActiveRecord to just return the values of those attributes, instead of instantiating and returning an Example model object.

Upvotes: 1

Hieu Pham
Hieu Pham

Reputation: 6707

MONTHS = %w( january february march april may june july august september october november december )

example.attributes.slice(*MONTHS)
=> {january: 12, february: 3, march: 3, april: 4, may: 5, june: 2, july: 4, august: 24, september: 4, october: 24, november: 4, december: 4}
example.attributes.slice(*MONTHS).values
=> [12, 3, 3, 4, 5, 2, 4, 24, 4, 24, 4, 4]

Upvotes: 0

Max Williams
Max Williams

Reputation: 32933

monthnames = %w(january february march april may june july august september october november december)
example_attributes.each do |attr_name, attr_value|
  if monthnames.include?(attr_name)
    @array_example << attr_value
  end
end

OR

@array_example += monthnames.collect{|monthname| example.attributes[monthname]}.reject(&:blank?)

Upvotes: 0

Ursus
Ursus

Reputation: 30056

months = %w(january february march) 
months.include? attr_name

Upvotes: 0

Related Questions