简体   繁体   中英

How to dynamically generate a map in Ruby

I have the following code

records.map do |record|
  {
    id: record.id,
    uuid: record.uuid
  }
end

but I would like portions of it to be created dynamically, ie if I had the array COLUMNS = ["id", "uuid", "name"]

How could I have it generate the below based on the array automatically?

records.map do |record|
  {
    id: record.id,
    uuid: record.uuid,
    name: record.name
  }
end

ie

records.map do |record|
  {
    COLUMNS[0]: record.COLUMNS[0],
    COLUMNS[1]: record.COLUMNS[1],
    COLUMNS[2]: record.COLUMNS[2]
  }
end

Thanks!

serializable_hash

You can convert any ActiveRecord objects to a Hash with serializable_hash and you can convert any ActiveRecord results to an Array with to_a, like below

records = YourModel.all
# for all fields 
records.to_a.map(&:serializable_hash)

# for specific fields
COLUMNS = ["id", "uuid", "name"]
records.to_a.map{ |r| r.serializable_hash(only: COLUMNS) }

for more info

https://api.rubyonrails.org/classes/ActiveModel/Serialization.html

Solved it like below

    def generate_map(record)
      testing = {}
      COLUMNS.each do |column|
        testing[column.to_sym] = record[column.to_sym]
      end
      return testing
    end

    records.map do |record| generate_map(record) end

A simple way would be something like this:

records.map do |record|
  COLUMNS.map do |column|
    [column.to_sym, record.public_send(column)]
  end.to_h
end

It would make more sense to store the column names as Symbol s than as String s, since Symbol is Ruby's standard data type for "labels of things".

You can do this with Ruby 2.1:

records.map { |x| [x, x] }.to_h

Also, if I wrote:

records = ["id", "uuid", "name"]
puts records.map { |x| [x, x + " value"] }.to_h

The results is:

{"id"=>"id value", "uuid"=>"uuid value", "name"=>"name value"}

if you are using older versions of Ruby, you could use inject/reduce.

You could surely improvise a bit.

COLUMNS = ["id", "uuid", "name"]

records.map do|record|
    result = {}
    COLUMNS.each{|column| result.merge!({column => (record.send(column) rescue '')})}
    result
end 

Well, I can see you answered that the record is an ActiveRecord model already.

Therefore, we have a very easy and simple way to accomplish that.

COLUMNS = [:id, :uuid, :name]
Record.select(*COLUMNS).map(&:serializable_hash)

In which Record is your ActiveRecord model.

You just need to select these COLUMNS from the Record and convert them to hashes.

References:

  1. https://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/select
  2. https://api.rubyonrails.org/classes/ActiveModel/Serialization.html
  3. https://riptutorial.com/ruby/example/6796/arrays-and-the-splat-----operator

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM