我正在尝试使用textarea和一个提交按钮创建一个表单,允许用户进行批量插入。例如,输入看起来像这样:
0001;MR A
0002;MR B
结果如下:
mysql> select * from members;
+------+------+------+
| id | no | name |
+------+------+------+
| 1 | 0001 | MR A |
+------+------+------+
| 2 | 0002 | MR B |
+------+------+------+
我对Rails很新,我不确定如何继续这个。我应该使用attr_accessor
吗?如何在表单视图中处理失败的验证?有什么例子吗?提前谢谢。
更新
根据MissingHandle的评论,我创建了一个Scaffold并用这个替换了Model的代码:
class MemberBulk < ActiveRecord::Base
attr_accessor :member
def self.columns
@columsn ||= []
end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
column :data, :text
validates :data, :create_members, :presence => true
def create_members
rows = self.data.split("\r\n")
@member = Array.new
rows.each_with_index { |row, i|
rows[i] = row.strip
cols = row.split(";")
p = Member.new
p.no = cols[0]
p.name = cols[1]
if p.valid?
member << p
else
p.errors.map { |k, v| errors.add(:data, "\"#{row}\" #{v}") }
end
}
end
def create_or_update
member.each { |p|
p.save
}
end
end
我知道代码远未完成,但我需要知道这是正确的方法吗?
答案 0 :(得分:1)
class MemberBulk < ActiveRecord::Base
#Tells Rails this is not actually tied to a database table
# or is it self.abstract_class = true
# or @abstract_class = true
# ?
abstract_class = true
# members holds array of members to be saved
# submitted_text is the data submitted in the form for a bulk update
attr_accessor :members, :submitted_text
attr_accessible :submitted_text
before_validation :build_members_from_text
def build_members_from_text
self.members = []
submitted_text.each_line("\r\n") do |member_as_text|
member_as_array = member_as_text.split(";")
self.members << Member.new(:number => member_as_array[0], :name => member_as_array[1])
end
end
def valid?
self.members.all?{ |m| m.valid? }
end
def save
self.members.all?{ |m| m.save }
end
end
class Member < ActiveRecord::Base
validates :number, :presence => true, :numericality => true
validates :name, :presence => true
end
因此,在此代码中,成员是一个数组,它是各个Member对象的集合。我的想法是,尽可能地,您希望将工作交给Member类,因为它实际上是绑定到数据库表的类,并且您可以期望标准的rails模型行为。为了实现这一点,我重写了所有ActiveRecord模型共有的两种方法:save和valid。 MemberBulk只有在所有成员都有效的情况下才有效,并且只有在保存所有成员的情况下才会计为保存。您可能还应该覆盖errors方法以返回其底层成员的错误,可能指示它在提交的文本中是哪一个。
答案 1 :(得分:-1)
最后我不得不从使用Abstract Class更改为Active Model(不知道为什么,但是当我升级到Rails v3.1时它停止工作)。这是工作代码:
class MemberBulk
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :input, :data
validates :input, presence: true
def initialize(attributes = {})no
attributes.each do |name, value|
send("#{name}=", value) if respond_to?("#{name}=")
end
end
def persisted?
false
end
def save
unless self.valid?
return false
end
data = Array.new
# Check for spaces
input.strip.split("\r\n").each do |i|
if i.strip.empty?
errors.add(:input, "There shouldn't be any empty lines")
end
no, nama = i.strip.split(";")
if no.nil? or nama.nil?
errors.add(:input, "#{i} doesn't have no or name")
else
no.strip!
nama.strip!
if no.empty? or nama.empty?
errors.add(:input, "#{i} doesn't have no or name")
end
end
p = Member.new(no: no, nama: nama)
if p.valid?
data << p
else
p.errors.full_messages.each do |error|
errors.add(:input, "\"#{i}\": #{error}")
end
end
end # input.strip
if errors.empty?
if data.any?
begin
data.each do |d|
d.save
end
rescue Exception => e
raise ActiveRecord::Rollback
end
else
errors.add(:input, "No data to be processed")
return false
end
else
return false
end
end # def
end