问题与ActiveRecord的二传手覆盖 [英] Issue with setter override on ActiveRecord

查看:99
本文介绍了问题与ActiveRecord的二传手覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是不完全的问题,这是相当对我如何与 write_attribute 当属性是一个对象,on Rails的活动记录。我希望这能对别人有用面临同样的问题。

This is not exactly a question, it's rather a report on how I solved an issue with write_attribute when the attribute is an object, on Rails' Active Record. I hope this can be useful to others facing the same problem.

让我举个例子来说。假设你有两个类,图书作者

Let me explain with an example. Suppose you have two classes, Book and Author:

class Book < ActiveRecord::Base
  belongs_to :author
end

class Author < ActiveRecord::Base
  has_many :books
end

很简单。但是,不管是什么原因,你需要重写作者 =上图书方法。由于我是新来的Rails,我跟着萨姆Ruby的敏捷Web开发建议使用Rails:使用 attribute_writer 私有方法。所以,我的第一次尝试是:

Very simple. But, for whatever reason, you need to override the author= method on Book. As I'm new to Rails, I've followed the Sam Ruby's suggestion on Agile Web Development with Rails: use attribute_writer private method. So, my first try was:

class Book < ActiveRecord::Base
  belongs_to :author

  def author=(author)
    author = Author.find_or_initialize_by_name(author) if author.is_a? String
    self.write_attribute(:author, author)
  end
end

不幸的是,这是行不通的。这就是我从控制台得到:

Unfortunately, this does not work. That's what I get from console:

>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author = "Lewis Carroll"
=> "Lewis Carroll"
>> book
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author
=> nil

看来,Rails的不承认它是一个对象,使虚无的attribuition后,笔者还是零!当然,我可以尝试 write_attribute(:AUTHOR_ID,author.id),但它并不能帮助时,笔者尚未保存(仍没有ID!)和我需要的对象一起保存(作者一定是只有当书是有效的保存)。

It seems that Rails does not recognize it is an object and makes nothing: after the attribuition, author is still nil! Of course, I could try write_attribute(:author_id, author.id), but it does not help when the author is not saved yet (it still has no id!) and I need the objects be saved together (author must be saved only if book is valid).

搜索经过大量的解决方案(和妄图许多其他的事情),我发现这条消息:<一href="http://groups.google.com/group/rubyonrails-talk/browse%5Fthread/thread/4fe057494c6e23e8">http://groups.google.com/group/rubyonrails-talk/browse%5Fthread/thread/4fe057494c6e23e8,所以最后我可能有一些工作code:

After search a lot for a solution (and try many other things in vain), I found this message: http://groups.google.com/group/rubyonrails-talk/browse%5Fthread/thread/4fe057494c6e23e8, so finally I could had some working code:

class Book < ActiveRecord::Base
  belongs_to :author

  def author_with_lookup=(author)
    author = Author.find_or_initialize_by_name(author) if author.is_a? String
    self.author_without_lookup = author
  end
  alias_method_chain :author=, :lookup
end

这一次,控制台是对我很好:

This time, the console was nice to me:

>> book = Book.new(:name => "Alice's Adventures in Wonderland", :pub_year => 1865)
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author = "Lewis Carroll"=> "Lewis Carroll"
>> book
=> #<Book id: nil, name: "Alice's Adventures in Wonderland", pub_year: 1865, author_id: nil, created_at: nil, updated_at: nil>
>> book.author
=> #<Author id: nil, name: "Lewis Carroll", created_at: nil, updated_at: nil>

这里的窍门是 alias_method_chain ,创建一个拦截器(在这种情况下, author_with_lookup ),并替代名称老二传手( author_without_lookup )。我承认它花了一些时间来了解这个安排,我会很高兴,如果有人照顾解释得很详细,但让我吃惊的缺乏有关此类问题的信息。我有谷歌有很多找到刚才一个职位,由标题最初似乎无关的问题。我是新来的Rails,那么,你认为球员:这是一个不好的做法

The trick here is the alias_method_chain, that creates an interceptor (in this case author_with_lookup) and an alternative name to the old setter (author_without_lookup). I confess it took some time to understand this arrangement and I'd be glad if someone care to explain it in detail, but what surprised me was the lack of information about this kind of problem. I have to google a lot to find just one post, that by the title seemed initially unrelated to the problem. I'm new to Rails, so what do you think guys: is this a bad practice?

推荐答案

我建议创建一个虚拟属性,而不是覆盖作者= 方法。

I recommend creating a virtual attribute instead of overriding the author= method.

class Book < ActiveRecord::Base
  belongs_to :author

  def author_name=(author_name)
    self.author = Author.find_or_initialize_by_name(author_name)
  end

  def author_name
    author.name if author
  end
end

那么你可以做很酷的事情喜欢把它应用到一个表单字段。

Then you could do cool things like apply it to a form field.

<%= f.text_field :author_name %>

将这项工作对于你的情况?

Would this work for your situation?

这篇关于问题与ActiveRecord的二传手覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆