Reputation: 1875
I have a model "Item", and I want to generate a bunch of Items with data taken from a CSV file. But I want to allow the user to select which data columns are used.
So my model "User" has a json attribute called Columns, telling which columns should be used from that user's CSV file. For example, if user.columns == {"title"=>"true","category"=>"false"}
, then the Title column should be used but the Category column shouldn't.
(Alternatively, I could only list the columns I want to include, like this: {"title"=>"included"}
, and later do something like user.columns.each {|c| c[0]}
to get an array of all the included columns.)
I have a method for generating Items based on the CSV data:
def create
#...
SmarterCSV.process(file).each do |row| #this line returns an array of all the rows in the CSV file
Item.create(title: row[:title], category: row[:category])
end
end
but how can I modify the method's parameters based on the contents of user.columns
? For the {"title"=>"true","category"=>"false"}
example, the method would just be Item.create(name: row[:title])
. Is it possible to dynamically generate a method like that?
I'm planning to have quite a lot of possible columns, so doing an if
conditional for every possibility is unfeasible.
Upvotes: 1
Views: 155
Reputation: 37507
I would add a method to your User
model to return the column names as symbols:
class User
def selected_columns
columns.select{|_,v| v == "true"}.keys.map(&:to_sym)
end
end
and then modify your item creation like so:
Item.create(row.slice(*user.selected_columns))
Upvotes: 1
Reputation: 5690
Item.create(name: row[:name])
also takes a hash, and can be written equivalently as Item.create({ name: row[:name] })
As such - you can build up the entire object in a hash each time; then slice
off any attributes that you don't want, and then pass to create
. So assuming you have:
user.columns
#=> {"name"=>"true","category"=>"false"}
Then you could write:
user_object = { "name" => row[:name], "category" => row[:category] }
#=> include all the possible attributes here
included_attributes = user.columns.select { |k, v| v == "true" }
#=> {"name"=>"true"}
Item.create( user_object.slice(*included_attributes.keys) )
#=> `Item` is created with only `name` attribute
Edit: as engineersmnky points out in the comments, row
is already a hash. This simplifies it further, and you could instead just write:
SmarterCSV.process(file).each do |row|
included_attributes = user.columns.select { |k, v| v == "true" }
Item.create( row.slice(*included_attributes.keys) )
end
Upvotes: 2