正确的方法prevent的ActiveRecord :: ReadOnlyRecord? [英] Proper way to prevent ActiveRecord::ReadOnlyRecord?

查看:94
本文介绍了正确的方法prevent的ActiveRecord :: ReadOnlyRecord?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前使用Rails 2.3.9。据我所知,指定:在查询中加入选项没有一个明确的:选择会自动将该返回读取任何记录-只要。我有一个情况我想更新的记录,虽然我已经知道了不同的​​方式来对待它,我不知道哪条路是preferred或正确的方式。

I'm currently using Rails 2.3.9. I understand that specifying the :joins option in a query without an explicit :select automatically makes any records that are returned read-only. I have a situation where I would like to update the records and while I've read about different ways to approach it, I was wondering which way is the preferred or "proper" way.

具体而言,我的情况是,我有如下的用户模式与主动命名范围,执行一个JOIN与订阅表:

Specifically, my situation is that I have the following User model with an active named scope that performs a JOIN with the subscriptions table:

class User < ActiveRecord::Base
  has_one :subscription

  named_scope :active, :conditions => { :subscriptions => { :status => 'active' } }, :joins => :subscription
end

当我称之为 User.active.all ,返回的用户记录都是只读的,所以如果,比如说,我称之为 update_attributes的!上的用户,的ActiveRecord :: ReadOnlyRecord 将得到提升。

When I call User.active.all, the user records that are returned are all read-only, so if, for instance, I call update_attributes! on a user, ActiveRecord::ReadOnlyRecord will be raised.

通过阅读各种渠道,这似乎是一个流行的方式来解决这个问题是通过添加:只读=&GT;假来查询。不过,我想知道以下内容:

Through reading various sources, it seems a popular way to get around this is by adding :readonly => false to the query. However, I was wondering the following:

  • 这是安全的吗?我明白为什么Rails的将其设置为只读摆在首位的原因是因为,根据的 Rails文档,他们将有不对应表中的列的属性。然而,从该呼叫使用生成的SQL查询 SELECT`雇员`。* 无论如何,这似乎是安全的,那么,什么是Rails的努力防范首先这样看来,Rails的应该防范的情况下,当:选择实际上是明确规定,这是实际的行为相反, 所以我是没有正确理解的自动设置只读标志的目的:加入
  • 这看起来像一个黑客这似乎是正确的命名范围的定义应该关心明确设置也:只读=&GT;假。我也怕副作用,如果指定的范围被链接与其他命名范围。如果我尝试的范围(如境外指定它,做 User.active.scoped(:只读=&GT;假)用户。范围的。(:只读=&GT;假)。主动),它似乎并没有正常工作
  • Is this safe? I understand the reason why Rails sets it to read-only in the first place is because, according to the Rails documentation, "they will have attributes that do not correspond to the table’s columns." However, the SQL query that is generated from this call uses SELECT `users`.* anyway, which appears to be safe, so what is Rails trying to guard against in the first place? It would appear that Rails should be guarding against the case when :select is actually explicitly specified, which is the reverse of the actual behavior, so am I not properly understanding the purpose of automatically setting the read-only flag on :joins?
  • Does this seem like a hack? It doesn't seem proper that the definition of a named scope should care about explicitly setting :readonly => false. I'm also afraid of side effects if the named scoped is chained with other named scopes. If I try to specify it outside of the scope (e.g., by doing User.active.scoped(:readonly => false) or User.scoped(:readonly => false).active), it doesn't appear to work.

我读过来解决这个问题的另一种方式是改变:加入:包括 。我明白这更好的行为,但有什么缺点这个(比订阅表中的所有列的不必要的阅读其他)?

One other way I've read to get around this is to change the :joins to an :include. I understand the behavior of this better, but are there any disadvantages to this (other than the unnecessary reading of all the columns in the subscriptions table)?

最后,我也可以检索查询使用记录ID通过调用 User.find_all_by_id(User.active.map(安培;:ID)),但我发现这更是一个解决办法,而不是一个可行的解决方案,因为它会产生一个额外的SQL查询。

Lastly, I could also retrieve the query again using the record IDs by calling User.find_all_by_id(User.active.map(&:id)), but I find this to be more of a workaround rather than a possible solution since it generates an extra SQL query.

是否还有其他可能的解决方案?什么是在这种情况下preferred解决方案?我读过的<一个给出的答案href="http://stackoverflow.com/questions/639171/what-is-causing-this-activerecordreadonlyrecord-error">$p$pvious这个的StackOverflow问题,但它似乎并没有让公众知道会被认为是正确的具体指导。

Are there any other possible solutions? What would be the preferred solution in this situation? I've read the answer given in the previous StackOverflow question about this, but it doesn't seem to give specific guidance of what would be considered correct.

在此先感谢!

推荐答案

我相信,这将是一贯的和可以接受的,这种情况下使用:包括而不是:加入。我认为,:加入只用在极少数特殊的情况下,而:包括是pretty的共同

I believe that it would be customary and acceptable in this case to use :include instead of :join. I think that :join is only used in rare specialized circumstances, whereas :include is pretty common.

如果你不打算更新所有的活跃用户,那么它可能是明智的做法是增加一个额外的命名范围或找到状态,以进一步缩小您所加载,这样你不加载额外的用户,用户&放大器;订阅不必要的。比如...

If you're not going to be updating all of the active users, then it's probably wise to add an additional named scope or find condition to further narrow down which users you're loading so that you're not loading extra users & subscriptions unnecessarily. For instance...

User.active.some_further_limiting_scope(:with_an_argument)
  #or
User.active.find(:all, :conditions => {:etc => 'etc'})

如果你决定,你仍然想使用:加入,并且只打算更新加载用户的一小部分,那么它可能是最好重装刚用户想要这样做之前进行更新的权利。如...

If you decide that you still want to use the :join, and are only going to update a small percentage of the loaded users, then it's probably best to reload just the user you want to update right before doing so. Such as...

readonly_users = User.active
# insert some other code that picks out a particular user to update
User.find(readonly_users[@index].id).update_attributes(:etc => 'etc')

如果你确实需要加载的所有的活跃用户,并且要坚持使用:加入,你可能会被更新大部分或全部的用户,那么你的想法重新加载它们与一组ID可能是你最好的选择。

If you really do need to load all active users, and you want to stick with the :join, and you will likely be updating most or all of the users, then your idea to reload them with an array of IDs is probably your best choice.

#no need to do find_all_by_id in this case. A simple find() is sufficient.
writable_users_without_subscriptions = User.find(Users.active.map(&:id))

我希望帮助。我哪个选项你去与好奇,或者如果你发现了另一个解决方案更适合您的方案。

I hope that helps. I'm curious which option you go with, or if you found another solution more appropriate for your scenario.

这篇关于正确的方法prevent的ActiveRecord :: ReadOnlyRecord?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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