【问题标题】:Ruby/rails: saving a sample of has_many relationship to database?Ruby/rails:将 has_many 关系的示例保存到数据库?
【发布时间】:2017-07-20 23:06:44
【问题描述】:

问这个问题:我正在做的一个学生项目,我修修补补太久了,但无法提出解决方案。

我有一个名为 Game 的类,一个游戏有很多引号。如果我创建一个游戏@game = Game.create,然后将其与角色@game.characters = [@character1, @character2] 关联。由于我的关联,我可以使用@game.quotes(返回数百个对象)访问这两个字符的所有引号。

我希望能够获取 10 个引号的样本,例如 @game.ten_quotes(对象数组)将返回 @game.quotes 的随机样本。我还希望将@game.ten_quotes 保存到数据库中。

我的第一个想法是在迁移中我需要一个新的 Game 属性:

class CreateGames < ActiveRecord::Migration[5.1]
  def change
    create_table :games do |t|
        t.text :state, default: "[]"
        t.boolean :completed, default: false
        t.something :ten_quotes
        # what would this look like if I'm saving an array of objects?
      t.timestamps
    end
  end
end

在下面的 Rails 控制器中,我能够生成十个引号,但我觉得我的工作方向错误:

class Game < ApplicationRecord
  has_many :game_logs
  has_many :characters, through: :game_logs
  has_many :quotes, through: :characters

  def generate_quotes
    if self.ten_quotes == []
      x = quotes.shuffle.sample(10)
      self.ten_quotes = x
    else
      return false
    end
  end
end

如何获取报价样本,将该样本与游戏实例相关联,然后将游戏实例一次保存到数据库中,以后没有机会覆盖?我需要一个新模型吗?

如果您愿意提供帮助,请提前致谢。否则,祝您有美好的一天!

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 activerecord associations


    【解决方案1】:
    class AddTenQuotesIdsColumnToGames < ActiveRecord::Migration[5.1]
      def change
        add_column :games, :ten_quotes_ids, :text
      end
    end
    
    class Game < ApplicationRecord
      has_many :game_logs
      has_many :characters, through: :game_logs
      has_many :quotes, through: :characters
    
      serialize :ten_quotes_ids, Array
    
      def ten_quotes
        if ten_quotes_ids.length == 10
          quotes.where(id: ten_quotes_ids)
        else
          ten_quotes = quotes.order('RANDOM()').limit(10) # for MySQL use `quotes.order('RAND()').limit(10)`
          update ten_quotes_ids: ten_quotes.map(&:id)
          ten_quotes
        end
      end
    end
    

    text 类型的列添加到名为ten_quotes_idsGame 模型中。在您的模型中,serializeten_quotes_ids 列作为Array。这使您可以将 Ruby 对象数组存储到数据库中。您可以存储quotes实例,但如果有更改,它们将不会与您的数据库保持同步,因此最好只存储ids,这样您就可以获取当前记录需求。

    在您的 ten_quotes 方法中,您正在检查 ten_quotes_ids 是否有 10 个元素,如果有,则根据这些 ids 查询 Gamequotes 并返回它们,或者选择随机一组 10 个 quotes 属于数据库中的 Game,更新 ten_quotes_ids 属性,并返回十个引号。

    【讨论】:

    • 这正是我想要的,谢谢。了解到我可以将属性创建为数组并在其中存储任何内容。感谢您花时间写这个答案。
    【解决方案2】:

    编辑 2

    根据您的评论,我删除了我的第一个想法,因为您的信息“一个报价应该属于许多样本”和“十个报价是针对一周前发生的游戏”,我的想法是为具有这种关系的样本创建新模型如下

    class Game < ApplicationRecord
      # -> quotes -> samples
      has_many :quotes, :dependent => :destroy
      accepts_nested_attributes_for :quotes,   :allow_destroy => :true  
      has_many :samples, through: :quotes
    end
    
    class Quote < ApplicationRecord
      belongs_to :game
      has_many :samples, :dependent => :destroy
      accepts_nested_attributes_for :samples,   :allow_destroy => :true 
    
    end
    
    class Sample < ApplicationRecord
      belongs_to :quote
    
      scope :just_last_week, lambda { where('created_at >= ?', 1.week.ago)}
    end
    

    我添加了accepts_nested_attributes_for 和allow_destroy 以使您更轻松地从父级创建子记录 这里是link,以防您想了解更多

    来自游戏控制器

    # if you want get samples and 
      # for specific game
      @game = Games.find(params[:id])
      @samples = @game.samples.limit(10) # this will get 10 samples from samples
      @samples = @game.samples.just_last_week.limit(10) # this will get 10 samples created last week
      # for samples that created last week no matter what game is
      @samples = Sample.all.just_last_week   
    

    【讨论】:

    • 通过这个方法你可以访问数据库中的游戏并查看样本是什么吗?例如,我想查看一周前发生的游戏的十句话是什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2012-06-12
    • 1970-01-01
    相关资源
    最近更新 更多