滑轨4和滑轨5的不同之处在于相同的代码作用不同

时间:2018-07-24 22:45:47

标签: ruby-on-rails ruby-on-rails-4 ruby-on-rails-5

我在这门课上有这四节课,表现很好:

class Rule < ActiveModelSerializers::Model
  # Required by ActiveModelSerializers in order to seralize this object
  # @return [Hash] with all the attributes accessible for serialization
  def attributes
   ...some attributes...
  end

  def initialize(args = {})
    super
    @some_custom_variable = ...something...
  end
  # This method is relevant
  def assign_attributes(args)
    args.each { |k, v| instance_variable_set("@#{k}", v) }
    some_custom_variable.assign_attributes(args)
  end
end

此类是从控制器的create操作中调用的,如下所示:

rule = Rule.new(permitted_params.symbolize_keys)
rule.save

我的问题是执行控制器代码时会调用assign_attributes(我知道这是因为我已经在其中插入了断点),这只是在rails 5中发生。

因此,相同的代码,控制器中的相同参数(由相同的测试生成)的行为有所不同。使用rails 5,代码永远不会以assign_attributes方法结束。

我的问题是,为什么在Rails 5上它会如此表现?为什么assign_attributes被触发?

2 个答案:

答案 0 :(得分:1)

在Rails 4中,assign_attributes method是ActiveRecord的一部分,在Rails 5中它是ActiveModel的一部分。 Rails5 CHANGELOG中提到了此更改,在升级Rails之前,每个人都会阅读。

大概ActiveModelSerializers::Model包含一个assign_attributes方法,该方法通过ActiveModel中的某个内容,而ActiveModel中的某个内容则认为它是在调用AM的assign_attributes而不是您的意外覆盖。

但是,该项目位于state of chaos中(要慷慨大方),因此很难找到源代码:

  

更改为0.10.x维护:

     
      
  • 0.10.x版本已成为庞大的维护版本。我们曾希望将其定型为1.0版本,但显然并非如此   将要发生。几乎没有维护者来自0.8、0.9或   较早的0.10仍在AMS上运行。我们将继续保持   在0-10-stable分支上为0.10.x,但是维护者不会在该分支上积极开发。      
        
    • 我们可以选择制作一个0.11.x(   0-11-stable)版本基于0-10-stable删除了   弃用。
    •   
  •   
     

AMS发生了什么

     
      
  • 自从AMS始于Rails 3.2以来,围绕AMS进行了很多改动,并且出现了许多新的库,并且JSON:API规范达到了1.0。
  •   
  • 如果要发布1.0版的AMS,它将需要以可使用ActiveJob的方式来解决一般的序列化需求   与不同的工人。
  •   
  • 下一个主要版本正在开发中。我们从简单开始,至少在一开始就避免了AMS的所有并发症   版本,尤其是所有来自猜测的隐式行为   序列化程序,关联的序列化程序,序列化   类型等。
  •   
  • ...
  •   

那是六个月前的事,GitHub上没有可用的代码了,该项目对我来说似乎已被放弃。

一个短期解决方案是重命名您的assign_attributes方法。长期的解决方法是完全替换ActiveModelSerializer,最好用正在积极维护的东西代替。 AMS README甚至提供some alternatives

  
      
  • jsonapi-rb是一种高性能且模块化的仅JSON:API的实现。周围有一个充满活力的社区,它产生了诸如JSON:API Suite之类的项目。
  •   
  • fast_jsonapi是来自Netflix团队的用于Ruby Objects的闪电般的快速JSON:API序列化程序。
  •   

答案 1 :(得分:0)

根据Rails 4Rails 5 docs,Rails本身是否会使用assign_attributes并没有任何意义。只是这是一种可以一次分配一堆属性的方法。

路轨4

  

允许您通过传入具有与属性名称匹配的键(又与列名称匹配)的属性哈希来设置所有属性。

路轨5

  

允许您通过传入具有与属性名称匹配的键的属性哈希来设置所有属性。

Rule.new调用或不调用Rule#assign_attributes是实现的一个怪癖。没有记录new会调用assign_attributes,因此您不能依赖Rails何时调用它。

此外,如果您已覆盖assign_attributes,则必须继续执行文档中记载的操作,这一点很重要。分别设置每个属性和一次设置所有属性之间应该没有功能上的区别。您似乎没有调用super,而是编写了自己的质量分配代码,并添加了自己的额外代码以将属性镜像到另一个对象。

还有一个问题是ActiveModelSerializers :: Model可能会如何干扰。


如果要在设置特定参数时采取措施,请改写关联的attribute=方法。

def foo=(value)
    ...
end

或者使用各种ActiveRecord::Callbacks,例如before_validation

或者因为您似乎正在尝试委派质量设置属性,所以请考虑是否使用delegation is the answer

delegate :this, :that, to: :some_custom_variable