通过has_one构建has_one的方法

时间:2018-11-10 21:40:00

标签: ruby-on-rails has-one-through

轨道5.1.2 Ruby 2.5.3

我知道可以通过多种方式暗示这种关系,但是,这个问题更多地是关于为什么以下内容不起作用而不是解决现实世界中的问题。

class _RoulettePageWidgetState extends State<RoulettePageWidget> with SingleTickerProviderStateMixin { Animation<double> _animation; Tween<double> _tween; AnimationController _animationController; math.Random _random = math.Random(); int position = 0; double getRandomAngle() { return math.pi * 2 / 25 * _random.nextInt(25); } @override void initState() { super.initState(); _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this); _tween = Tween(begin: 0.0, end: getRandomAngle()); _animation = _tween.animate(_animationController) ..addListener(() { setState(() {}); }); } void setNewPosition() { _tween.begin = _tween.end; _animationController.reset(); _tween.end = getRandomAngle(); _animationController.forward(); } @override Widget build(BuildContext context) { return Container( child: Column( children: <Widget>[ Center( child: Transform.rotate( angle: _animation.value, child: Icon( Icons.arrow_upward, size: 250.0, ), )), Expanded( child: Container(), ), RaisedButton( child: Text('SPIN'), onPressed: setNewPosition, ) ], ) ); } } 设置

has_many

在上面的class Subscriber < ApplicationRecord has_many :subscriptions, inverse_of: :subscriber has_many :promotions, through: :subscriptions, inverse_of: :subscriptions accepts_nested_attributes_for :subscriptions accepts_nested_attributes_for :promotions end class Subscription < ApplicationRecord belongs_to :subscriber, inverse_of: :subscriptions belongs_to :promotion, inverse_of: :subscriptions end class Promotion < ApplicationRecord has_many :subscriptions, inverse_of: :promotion has_many :subscribers, through: :subscriptions, inverse_of: :subscriptions accepts_nested_attributes_for :subscriptions accepts_nested_attributes_for :subscribers end 模型中,该模型被设置为使用Subscriber关系,如下所示:

has_many

在此之后,我希望s = Subscriber.new s.subscriptions.build # OR s.promotions.build Subscriber关系中的行为方式相同

has_one设置

has_one

但是,尝试使用等效的class Subscriber < ApplicationRecord has_one :subscription, inverse_of: :subscriber has_one :promotion, through: :subscription, inverse_of: :subscriptions accepts_nested_attributes_for :subscription accepts_nested_attributes_for :promotion end class Subscription < ApplicationRecord belongs_to :subscriber, inverse_of: :subscription belongs_to :promotion, inverse_of: :subscriptions end class Promotion < ApplicationRecord has_many :subscriptions, inverse_of: :promotion has_many :subscribers, through: :subscriptions, inverse_of: :subscription accepts_nested_attributes_for :subscriptions accepts_nested_attributes_for :subscribers end 构建方法来构建嵌套的promotion关联会导致has_one错误

NoMethodError (undefined method 'build_promotion' for #<Subscriber:0x00007f9042cbd7c8>)

但是,这确实可行:

s = Subscriber.new
s.build_promotion

我认为应该以建立s = Subscriber.new s.build_subscription 的相同方式来建立嵌套的has_one关系,这是合乎逻辑的。

这是错误还是故意的?

1 个答案:

答案 0 :(得分:1)

检查代码,当您调用has_one时,仅当反射是“可构造的”时,它才会创建build_create_create_..!方法

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/associations/builder/singular_association.rb#L16

define_constructors(mixin, name) if reflection.constructable?

现在,检查constructable?方法,它返回calculate_constructable https://github.com/rails/rails/blob/ed1eda271c7ac82ecb7bd94b6fa1b0093e648a3e/activerecord/lib/active_record/reflection.rb#L452

的结果

对于HasOne类,如果使用:through选项https://github.com/rails/rails/blob/ed1eda271c7ac82ecb7bd94b6fa1b0093e648a3e/activerecord/lib/active_record/reflection.rb#L723

,它将返回false。
def calculate_constructable(macro, options)
  !options[:through]
end

所以,我想说这不是错误,它是设计使然。不过我不知道原因,也许听起来很合逻辑,但是我想有些事情要考虑的并不那么简单。