Ruby on rails Rails模型法中的无限循环

Ruby on rails Rails模型法中的无限循环,ruby-on-rails,recursion,Ruby On Rails,Recursion,用例 def fill_once unless self.box_filled? # Get a random product from the user's recommendations product = self.subscription.user.recommended_product_records[rand(self.subscription.user.recommended_product_records.length - 1)] # Make sur

用例

def fill_once
  unless self.box_filled?
    # Get a random product from the user's recommendations
    product = self.subscription.user.recommended_product_records[rand(self.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless self.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        product.add_to_box_credits(self.subscription, "sample")
      else
        unless product.full_price_credits.nil?
          product.add_to_box_credits(self.subscription, "full")
        end
      end
      self.save!
    end
    self.fill_once # Here's the recursion
  end
end
如果用户没有在他们的箱子里装满他们的信用限额(默认为6)以内的产品,则会在箱子模型上调用一个方法,为他们装满产品

代码指南

def fill_once
  unless self.box_filled?
    # Get a random product from the user's recommendations
    product = self.subscription.user.recommended_product_records[rand(self.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless self.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        product.add_to_box_credits(self.subscription, "sample")
      else
        unless product.full_price_credits.nil?
          product.add_to_box_credits(self.subscription, "full")
        end
      end
      self.save!
    end
    self.fill_once # Here's the recursion
  end
end
框中的信用数由
box\u credits
给出,它循环遍历框中的所有产品并返回它们的总值。这似乎奏效了

布尔方法
box\u filled?
检查
box\u积分
方法是否等于或大于可用积分数(订阅积分)

fill\u once
方法应将产品添加到盒子中,直到盒子被填满(
box\u filled?
返回
true
)。当
box\u学分
等于可用学分数时,会发生这种情况

代码

def fill_once
  unless self.box_filled?
    # Get a random product from the user's recommendations
    product = self.subscription.user.recommended_product_records[rand(self.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless self.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        product.add_to_box_credits(self.subscription, "sample")
      else
        unless product.full_price_credits.nil?
          product.add_to_box_credits(self.subscription, "full")
        end
      end
      self.save!
    end
    self.fill_once # Here's the recursion
  end
end
box\u filled?
方法如下所示:

def box_filled?
  subscription = self.subscription
  if self.box_credits >= subscription.credits
    return true
  else
    return false
  end
end
box\u积分
由以下方法确定:

def box_credits
  count = 0
  unless self.added_product_hashes.nil?
    # Takes product hashes in the form {id, size, method}
    self.added_product_hashes.each do |product_hash|
      # Add credits to the count accordingly
      if product_hash["method"] == "credits"

        # Depending on the product size, add the corresponding amount of credits
        if product_hash["size"] == "sample"
          # Get the credit cost for a product sample
          cost = Product.find(product_hash["id"].to_i).sample_price_credits
          count += cost
        elsif product_hash["size"] == "full"
          # Get the credit cost for a full product
          cost = Product.find(product_hash["id"].to_i).full_price_credits
          count += cost
        else
          next
        end

      else
        next
      end
    end
  end

  return count
end
问题

fill\u once
永远运行:它似乎忽略了
,除非self.box\u已填充?
有条件

尝试的解决方案

我尝试从
fill\u once
方法中删除对
fill\u once
的递归调用,并将其拆分为一个
直到
循环(
直到box\u filled?…fill\u once…
),但没有乐趣

更新

def fill_once
  unless self.box_filled?
    # Get a random product from the user's recommendations
    product = self.subscription.user.recommended_product_records[rand(self.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless self.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        product.add_to_box_credits(self.subscription, "sample")
      else
        unless product.full_price_credits.nil?
          product.add_to_box_credits(self.subscription, "full")
        end
      end
      self.save!
    end
    self.fill_once # Here's the recursion
  end
end
多个相同的产品也被添加。我认为问题在于更新的记录没有被操作——只有原始实例。例如,
除非自行添加的产品ID包括在内?product.id
检查原始的box实例,而不是更新的记录,在添加的产品id中看不到任何产品,并将找到的每个产品都放入


解决方案

好了,问题解决了。正如所怀疑的那样,更新的记录没有被传递到迭代器中。我是这样解决的:

# Add one random user recommended product to the box
def fill_once(box=self)
  unless box.box_filled?
    # Get a random product from the user's recommendations
    product = box.subscription.user.recommended_product_records[rand(box.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless box.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "sample")
      else
        unless product.full_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "full")
        end
      end
    end
    fill_once(box)
  end
end
# Add one random user recommended product to the box
def fill_once(box=self)
  unless box.box_filled?
    # Get a random product from the user's recommendations
    product = box.subscription.user.recommended_product_records[rand(box.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless box.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "sample")
      else
        unless product.full_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "full")
        end
      end
    end
    fill_once(box)
  end
end

使用Ruby的默认参数,默认值为
self
,但选择使用更新的记录,允许我根据需要多次通过流传递记录。

,除非self.added\u product\u id.include?product.id
表示不会将重复的产品添加到框中。因此,如果所有推荐的产品都添加到box中,但总积分小于box\u积分,可能会导致无限循环。我不确定,但这可能是原因

你可以加上

puts "Box credits #{self.box_credits} vs. credits: #{self.subscription.credits} "
以前

self.fill_once # Here's the recursion

查看是否发生这种情况。

解决方案

好了,问题解决了。正如所怀疑的那样,更新的记录没有被传递到迭代器中。我是这样解决的:

# Add one random user recommended product to the box
def fill_once(box=self)
  unless box.box_filled?
    # Get a random product from the user's recommendations
    product = box.subscription.user.recommended_product_records[rand(box.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless box.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "sample")
      else
        unless product.full_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "full")
        end
      end
    end
    fill_once(box)
  end
end
# Add one random user recommended product to the box
def fill_once(box=self)
  unless box.box_filled?
    # Get a random product from the user's recommendations
    product = box.subscription.user.recommended_product_records[rand(box.subscription.user.recommended_product_records.length - 1)]
    # Make sure the product hasn't already been included in the box
    unless box.added_product_ids.include? product.id
      # If fresh, add the product to the box, size-dependently
      unless product.sample_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "sample")
      else
        unless product.full_price_credits.nil?
        box = product.add_to_box_credits(box.subscription, "full")
        end
      end
    end
    fill_once(box)
  end
end

使用Ruby的默认参数,默认值为
self
,但是选择使用更新的记录,允许我根据需要多次通过流传递记录。

看起来您可以稍微重构此代码,还有许多注释,如
#将成本添加到计数
,这是不好的做法,但我想说明我的想法!关于递归问题有什么想法吗?你的想法有点不可读,许多不必要的注释,
self
在你可以删除它的地方,结合
除非。。其他的结束
相同,除非有什么.nil?
,我不确定,但希望如果你只是重构你的示例,你会在没有帮助的情况下找到解决方案)@IS04我很难理解你的评论,所以也许你也可以重构它?;)有没有更好的方法来编写
,除非是.nil?这是一个好主意,让我尝试一个更大的产品列表。无论哪种方式,代码都不能处理这个问题,这是一个问题。也许它应该计算最大可能的数量,如果无法填充该框,则引发异常。每次尝试一次。也许
fill\u once
应该是一个步骤,循环本身被提取到它自己的方法中(处理这类事情)。嘿,大家,我们在这里检查代码:D有一个,同意!我现在已经处理好了。如果我们可以尝试寻找递归问题的答案,那就很方便了?遗憾的是,这并不能解决问题——产品不断地添加到盒子中,而不考虑约束。多个相同的产品也被添加。我认为问题在于更新的记录没有被操作——只有原始记录。例如,
除非自行添加的产品ID包括在内?product.id
检查原始的box实例,而不是更新的记录。我认为它并没有解决所有问题,我标记您迁移到CodeReview的问题,您可能需要其他审阅建议。