Hi I'm trying this tuto on Rails cast (Importing csv Excel file). And I'm having an error on this line product.attributes = row.to_hash.slice(*accessible_attributes)
undefined local variable or method
accessible_attributes' for #`
this is my model.
class Product < ActiveRecord::Base
require 'roo'
validates_presence_of :price
#attr_accessible :name, :price, :released_on #I removed this line (rails 4)
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |product|
csv << product.attributes.values_at(*column_names)
end
end
end
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash.slice(*accessible_attributes)
product.save!
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then Roo::Csv.new(file.path)
when ".xls" then Roo::Csv.new(file.path)
when ".xlsx" then Roo::Csv.new(file.path)
else raise "Unknown file type: #{file.original_filename}"
end
end
end
end on my controller I defined the product_params
def product_params
params.require(:product).permit(:name, :price, :released_on)
end
my csv that I'm trying to import looks like this:
id,name,realased_on,price,created_at,updated_at
1,Acoustic Guitar,2012-10-03,3456.54,2013-12-09 00:00:23 UTC, 2012-12-08 23:45:46 UTC
Actually accessible_attributes
fetch that columns which are declare attr_accessible
in model but in rails 4 they have removed the attr_accessible
from model and used the strong_parameter instead of that so for this make an method of same name accessible_attributes
in his model then inside that method declare that columns array which are you want. Such as:
def accessible_attributes
[col1_name, col2_name, ....]
end
In working on this Railscast under Rails 4.1, I got the method to work by replacing accessible_attributes with row.to_hash.keys.
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash.slice(*row.to_hash.keys)
product.save!
end
end
Using the accepted solution as is didn't work out for me. I needed to add "self." to the method definition to make it work.
Another way, if the only place you are calling accessible_attributes is within self.import, is defining the fields you are looking for as a local array variable.
def self.import(file)
accessible_attributes = ['my_attribute_name1','my_attribute_name2', '...']
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
cae = find_by_id(row["id"]) || new
cae.attributes = row.to_hash.slice(*accessible_attributes)
cae.save!
end
end
To answer the previous question that why validation message shows "Price can't be blank". I think it may due to that the data is saved as General format in Excel. I encountered a similar issue and the error message went away after I changed it to text format. I don't know the reason but give it a try.