rails 4中有序的has_many关联

时间:2016-02-07 10:44:45

标签: ruby-on-rails ruby has-many

我认为这不是一个不常见的要求,但我无法找到合适的解决方案。

我有一个配方模型,其中n:1与指令的关系。

  <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Hidden" Margin="0,5,0,0" Grid.Row="1">
    <StackPanel.Triggers>
        <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="btnRestartWiFi1_Copy19">
            <BeginStoryboard>
                <Storyboard>
                    <!--<DoubleAnimation Storyboard.TargetName="Stk1" Storyboard.TargetProperty="Opacity" To="0"/>-->
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                            <DiscreteObjectKeyFrame Value="{x:Static local:ViewModel.Collapsed}">
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                    </ObjectAnimationUsingKeyFrames>                            
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </StackPanel.Triggers>
   <StackPanel x:Name="MenuAppMemTopApps1" Height="485" Width="534">
   ...

不,我想手动订购食谱中的说明。所以我的第一种方法是在指令中添加位置属性并添加以下内容。

class Recipe < ActiveRecord::Base
    has_many :instructions, autosave: true, class_name: 'RecipeInstruction'
end

我在配方控制器中设置了position属性。这个解决方案有两个缺点:

  1. 我必须在任何地方设置指令的位置属性,我在其中创建指令。
  2. 订单声明仅影响db的提取。当我在非持久化配方/指令中更改位置属性时,它不会影响顺序。
  3. 在其他编程语言中,我会覆盖此关系的getter和setter。该关联的哪些运营商我必须覆盖以涵盖向关系添加对象的所有可能性?

    PS:我知道我可以覆盖&lt;&lt;该协会的运营商:

    class Recipe < ActiveRecord::Base
        has_many :instructions, -> { order('position ASC') }, autosave: true, class_name: 'RecipeInstruction'
    end
    

    但=运营商不能以这种方式被覆盖,可以吗?

    编辑:现在我知道如何覆盖=运算符。我是否必须覆盖所有可能性,或者是否有一个方法被每个操作员调用以添加指令,如push? 我怎样才能强制重新加载&#34;当我改变一个或多个指令的位置属性时相关对象的哪些?

    PPS:覆盖设置器以获取指令 我尝试了两种变体,但在提交表单后没有被rails调用。但指定给配方的说明。所以必须有另一个选项,所以设置它/覆盖setter:

    has_many :instructions, -> { order('position ASC') }, autosave: true, class_name: 'RecipeInstruction' do
        def << *args
        end
    end
    

    PPPS:设置位置的解决方案

    采取第一步。我认为这是初始化位置属性的一个很好的解决方案:

    has_many :instructions, -> { order('position ASC') }, autosave: true, class_name: 'RecipeInstruction' do
        def instructions=(instructions)
            raise error
        end
    end
    
    has_many :instructions, -> { order('position ASC') }, autosave: true, class_name: 'RecipeInstruction'
    
    def instructions=(instructions)
            raise error
    end
    

3 个答案:

答案 0 :(得分:1)

感谢您的帮助。我终于找到了一个很好的解决方案:

https://github.com/swanandp/acts_as_list

这是一个很好地解决问题的插件。

编辑:但仅适用于持久性记录。我认为这是活跃的记录风格&#39;。

答案 1 :(得分:0)

你可以在Rails中编写getter / setter。例如,要为Recipe对象(在模型中)编写getter和setter,

def position
  where('some req').order('some way')
end

def position=(arg1)
  self.something = arg1
end

这就是你覆盖=运算符的方式。

答案 2 :(得分:0)

我认为你已经有了答案;要提供可能帮助的内容,您可以在扩展has_many关联时访问proxy_association个对象:

has_many :instructions, -> { order('position ASC') }, autosave: true, class_name: 'RecipeInstruction' do
    def x
       proxy_association.target
    end
end

根据这些docs,您还可以访问record.association(:name)个对象:

@recipe = Recipe.find x
@recipe.instructions = @recipe.association(:instructions).target #-> returns collection of instructions

这样您就可以访问一系列说明,从中可以提取positions

@positions = @recipe.association(:instructions).target.select { |k,v| key.to_s.match(/^position\d+/) }

还有reload方法:

person.pets.reload # fetches pets from the database
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]

可悲的是,我没有任何内容可以插入<< / .destroy方法。