2017-06-06 5 views
1

Ich habe ein Modell "Item", und ich möchte eine Reihe von Items mit Daten aus einer CSV-Datei generieren. Aber ich möchte dem Benutzer erlauben, auszuwählen, welche Datenspalten verwendet werden.Wie kann ich dynamisch Parameter für eine create-Methode generieren?

So hat mein Modell "Benutzer" ein Json-Attribut namens Spalten, die angibt, welche Spalten aus der CSV-Datei dieses Benutzers verwendet werden sollten. Zum Beispiel, wenn user.columns == {"title"=>"true","category"=>"false"}, dann sollte die Titel Spalte verwendet werden, aber die Kategorie Spalte sollte nicht. (Alternativ könnte ich nur die Spalten Liste I enthalten sein sollen, wie folgt aus:. {"title"=>"included"}, und später so etwas wie user.columns.each {|c| c[0]} tun ein Array aller eingeschlossenen Spalten zu bekommen)

Ich habe eine Methode für Objekte zu erzeugen basierend auf den CSV-Daten:

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 

aber wie kann ich die Methode der Parameter basierend auf den Inhalt von user.columns ändern? Für das Beispiel wäre das Verfahren einfach Item.create(name: row[:title]). Ist es möglich, eine solche Methode dynamisch zu generieren?

Ich plane, eine ganze Reihe von möglichen Spalten zu haben, so dass eine if Bedingung für jede Möglichkeit nicht machbar ist.

+0

Es ist mir nicht klar, die Zuordnung zwischen den Spaltennamen und was Sie in den 'create' Parameter benötigen. Aber es scheint, als ob Sie 'user.columns' modifizieren sollten, um etwas anderes zurückzugeben (oder eine andere Benutzermethode dafür zur Verfügung stellen) –

+0

@MarkThomas Sorry, wenn ich unklar war, möchte ich Parameter für meine' create' Aktion basierend auf dem Inhalt generieren von 'user.columns'. Wenn zum Beispiel 'user.columns = {" included_column "=>" true "," eine andere_included_column "=>" true "," not_included_column "=>" false "}', dann würden die 'create' Parameter' Item sein. create (included_column: row [: included_column], andere_included_column: row [: another_included_column]) '. Ist das sinnvoll? 'not_included_column' wäre kein Parameter, weil es in' user.columns' false ist. –

+0

Was enthält 'row'? –

Antwort

2

Item.create(name: row[:name]) nimmt auch einen Hash und kann äquivalent als Item.create({ name: row[:name] })

Als solche geschrieben werden - man kann das gesamte Objekt in einem Hash jedes Mal aufzubauen; dann slice aus alle Attribute, die Sie nicht möchten, und dann an create übergeben. Also vorausgesetzt, Sie haben:

user.columns 
#=> {"name"=>"true","category"=>"false"} 

Dann könnten Sie schreiben:

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: als engineersmnky in den Kommentaren weist darauf hin, row ist bereits ein Hash. Dies vereinfacht es weiter, und Sie könnten stattdessen nur schreiben:

SmarterCSV.process(file).each do |row| 
    included_attributes = user.columns.select { |k, v| v == "true" } 
    Item.create(row.slice(*included_attributes.keys)) 
end 
+1

Zeile ist bereits ein 'Hash' und hat Schlüssel für' name' und 'category' warum nicht nur das nutzen? – engineersmnky

+0

@engineersmnky: guter Punkt! – gwcodes

+1

'keys.map (&: to_sym)' :) weil die "row" -Schlüssel scheinbar Symbole sind und die Spaltenschlüssel Strings sind. Entweder das oder preprocess die 'user.columns' mit' symbolize_keys' – engineersmnky

1

ich eine Methode, um Ihre User Modell hinzufügen würde die Spaltennamen als Symbole zurück:

class User 
    def selected_columns 
    columns.select{|_,v| v == "true"}.keys.map(&:to_sym) 
    end 
end 

und dann Artikel Schaffung ändern wie also:

Item.create(row.slice(*user.selected_columns)) 
Verwandte Themen