如何创建更新Child的属性Rails的before_action

时间:2015-06-24 16:47:01

标签: ruby-on-rails nested update-attributes

对于此应用程序,App有许多Elements,每个Features都有许多Elements。每次AppsController#show运行时,我都想更新Features个属性。但是,我遇到了一个问题,因为我必须挖掘每个Element的@app.elements.features。我似乎无法从我的应用控制器(或features)拨打App's Show View

我在Elements上嵌入了列出应用FeaturesElementsController#show的表格,所以我不能称之为ElementsController或类似的东西。 ,因为那时它永远不会得到更新。我必须找到某种方法在AppsControllerbefore_action :set_completion, only: :show def set_completion @app = App.find(params[:id]) @app.update_attribute(:completion_status, (((@app.elements.where(completion: true).count) / (@app.elements.count).to_f) * 100 ) ) end 中调用此操作,但这对我来说听起来并非如此。

这是我到目前为止所做的,现在我不知道接下来应该做些什么。什么是完成这项工作的最佳方式?

我的应用控制器(父级):

  def update_feature_completion
  @app = App.find(params[:app_id])
      @element.update_attribute(:element_feature_completion,      
      (@element.features.where(completion: true).count)
      )
  end

元素控制器(子):

def set_completion
@parent = Parent.find(params[:id])

  @parent.childs.each do |child|
        if (child.childs_childs.where(completion: true).count) == (child.childs_childs.count) #if all childs_childs of the child are completed...
          then child.update_attribute(:completion, true) #...mark the child as completed.
            else child.update_attribute(:completion, false) #if all childs_childs of the child are not completed, then mark the child as not completed
        end
        #changes child completion status to % of childs_childs completed
        child.update_attribute(:child_completion_status,
          child.childs_childs.where(completion: true).count / child.childs_childs.count.to_f
          )
        @parent.update_attribute(:parent_completion_status,
            @parent.childs.child_completion_status.sum
          )

  end
end

修改 到目前为止我所拥有的(不是简单的):

class Parent < ActiveRecord::Base
  belongs_to :user
  has_many :children, dependent: :destroy
  has_many :childs_children, dependent: :destroy
  accepts_nested_attributes_for :children
  accepts_nested_attributes_for :childs_childs
end

父模型

class Child < ActiveRecord::Base
  belongs_to :parent
  has_many :childs_children, dependent: :destroy
  accepts_nested_attributes_for :childs_children
end

儿童模型

class childs_child < ActiveRecord::Base
  belongs_to :child
  belongs_to :parent
end

儿童的孩子模型

{{1}}

2 个答案:

答案 0 :(得分:1)

这可能最终会让你在后面的路上咬你。每次GET请求到达显示页面时数据库中数据更改的想法都可能导致服务器不必要的压力。想想那些击中您网页的所有网页抓取工具。他们会无意中触发这些数据库事务。

如果要对任何持久数据进行更改,则应通过POST方法完成。操作回调通常不适用于此类工作,通常只应用于身份验证和缓存等操作。那么我可以提供替代解决方案吗?

所以我们从深层嵌套的关系开始,这很好。但是,当我们对应用程序#how的GET请求发生时,我们不必经常进行这些计算,而是首先要查看导致这些更改的原因。您的数据似乎只会在功能更新完成后才会真正更改。这是您应该强制进行这些更改的地方。那么如果你做了类似的事情呢

让我们尝试采用RESTful方法来解决这个问题。由于功能标记为完整,因此还应更新其各自的元素和应用程序。我们还假设在没有将每个要素标记为完整的情况下,元素不能被标记为完整。

在您的应用程序#show页面上我假设您正在显示所有应用程序的元素和元素从属功能。我想你会希望你的用户点击一个功能上的按钮,该功能将该功能标记为完整。因此,让我们制作一条允许我们这样做的RESTful路线。

配置/ routes.rb中

resources :features do 
  member do
    post 'complete' # features#complete
  end
end

所以现在我们有一个RESTful路由,它将在FeaturesController中寻找完整的动作。

features_controller.rb

def complete
  if @feature.mark_as_complete
     # show some message that says "You successfully completed 'Feature A', Good job!"
  else
     #  Respond with nasty error message of why this request couldn't process
  end 
end

所以现在你有一个适用于该功能的动作。现在,您需要做的就是在遍历每个元素的功能时在您的应用#show页面中创建一个链接

应用程序/视图/应用/ show.html.haml

- @app.elements.each do |element|
  - element.features.each do |feature|
    = feature.name
    = link_to complete_feature_path(feature), method: :post

当用户完成每项功能时,他们可以点击将发布帖子方法的链接发送到功能#完成操作

class Feature < ActiveRecord::Base
  def mark_as_complete
    self.update_attributes(completion: true)
    self.element.update_completion_status
  end
end

class Element < ActiveRecord::Base
  def update_completion_status
    if (self.feautres.where(completion: true).count) == (self.features.count) # if all features are complete
      self.update_attributes(completion: true)
      self.update_attributes(feature_completion_status: calculate_percent_complete)
      self.app.update_completion_status
    else
      self.update_attributes(feature_completion_status: calculate_percent_complete)
    end
  end

  private
    def calculate_percent_complete
      self.features.where(completion: true).count / child.childs_childs.count.to_f
    end
end

class Feature < ActiveRecord::Base
  def mark_as_complete
    self.update_attributes(completion: true)
    self.element.update_completion_status
  end
end

class App < ActiveRecord::Base
  def update_completion_status
    # similar to that of Element I assume
  end
end

这样,只有在发出POST请求以将功能标记为已完成时,才会更新相应的数据。您应该在应用程序中执行的所有操作#show action是提供要显示的相应对象。

答案 1 :(得分:0)

最后一段代码如下:

@parent.update_attribute(:parent_completion_status,
   (@parent.children.sum(:child_completion_status) / @parent.children.count) * 100
    )

这基本上通过找出所有:parent_completion_status完成的百分比来找到children完成的百分比。

我知道这令人困惑,但我相信那里的某个人能够理解它。当我提出这个问题时,我无法以原来想要的方式解决这个问题。

建议如果您尝试执行类似的操作,请尝试按照我所做的步骤进行操作,除非有一种更简单的方法适用于您。