【问题标题】:How to add dynamic value for a column in ruby on rails model with Active Record Callbacks如何使用 Active Record 回调为 ruby​​ on rails 模型中的列添加动态值
【发布时间】:2020-05-20 23:10:34
【问题描述】:

我的 rails 应用程序中有一个模型 Document。它有列namekey

在我的create 操作控制器中,我从前端获取文档名称,并使用securerandomkey 动态设置一个值。

我对这种情况的实现是:

文档模型

class Document < ApplicationRecord
    belongs_to :user
    validates :key, presence: true, uniqueness: true
end

文档控制器

class DocumentsController < ApplicationController
    def create
        current_user.documents.create(create_document_params)
        redirect_to '/'
    end

    private
    def create_document_params
        params.require(:document).permit(:name).merge(key: "#{SecureRandom.hex(6)}#{Time.now.to_i}")
    end
end

这种方法的问题是动态键逻辑在控制器中,我认为它应该是文档模型的一部分。

为此,我尝试在 Document 模型中使用 Active Record Callbacksbefore_create。 我将安全随机密钥逻辑移动到 Document 模型中,如下所示:

class Document < ApplicationRecord
    belongs_to :user
    validates :key, uniqueness: true


    before_create do
        self.key = "#{SecureRandom.hex(6)}#{Time.now.to_i}"
    end
end

但现在我的问题是,每当我调用 createnew key 时,值总是相同的。但它应该在每次create 调用之前随机生成。

在 Rails 控制台中

u = User.find_by(user_name: "random")
u.documents.new(name: 'Yolo 1') // key: "89c9013c191a1589398865"
u.documents.new(name: 'Yolo 2') // key: "89c9013c191a1589398865"

我做错了什么?

编辑:添加 Gemfile :

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.3'

gem 'rails', '~> 6.0.3'
gem 'sqlite3', '~> 1.4'
gem 'puma', '~> 4.1'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 4.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
gem 'bcrypt', '~> 3.1.7'
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
gem 'web-console', '>= 3.3.0'
gem 'listen', '~> 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
gem 'capybara', '>= 2.15'
gem 'selenium-webdriver'
gem 'webdrivers'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem "rspec-rails", "~> 4.0"

数据库迁移:

class CreateDocuments < ActiveRecord::Migration[6.0]
    def change
        create_table :documents do |t|
            t.string :name,
            t.string :key, index: {unique: true}, null: false
            t.references :user
            t.timestamps
        end
    end
end

【问题讨论】:

  • 相同的值?有趣...您的文件记录有什么价值?您正在使用控制器创建或使用rails console进行测试?
  • 其他:您需要从控制器中删除 #merge
  • 是的,我在尝试Active Record Callbacks 时删除了merge,我正在尝试使用rails console
  • 对于每个doc = current_user.documents.create(name: 'some name') doc.key 都是一样的。

标签: ruby-on-rails activerecord rails-activerecord ruby-on-rails-6 rails-models


【解决方案1】:

我在我的应用程序上复制了您的场景,并且可以重现您的错误。 此行为与 validates 方法有关。我删除了它及其作品。

为了保持验证,我found this other answer

# frozen_string_literal: true

class Document < ApplicationRecord
  before_create :assing_key

  belongs_to :user

  validates :key, presence: true, uniqueness: true, allow_blank: true

  private

  def assing_key
    self.key = "#{SecureRandom.hex(6)}#{Time.now.to_i}"
  end
end

我添加allow_blank: true

您可以测试仅删除presence 而不是添加allow_blank。享受吧。

【讨论】:

  • 您好,感谢您的回答。我尝试了您的解决方案,但它不起作用,问题仍然存在。是因为我的数据库迁移吗? t.string :key, index: {unique: true}, null: false ?
  • 您的迁移不会影响模型范围。这是数据库的规则。否则,请尝试删除您的 validates 方法并返回结果。
  • 您也可以查看模型上的错误信息。 doc = Document.create(name: "foo")。在doc.errors 之后查看具体消息。
  • 我得到的错误是密钥::key=&gt;[{:error=&gt;:taken, :value=&gt;"89c9013c191a1589398865"}],这是因为它没有创建新密钥。
  • 这很奇怪...像我的示例类一样:在类中移动before_create 第一行,创建一个私有方法将您的密钥作为符号传递给before_create 并删除@987654333 @ 方法。让课堂更清晰,避免可疑部分。
【解决方案2】:

我不确定您是如何创建文档的,因为您在 key 上验证了 presence: true。使用doc = current_user.documents.create(name: 'some name') 创建文档时会出现错误{:key=&gt;["can't be blank"]},因为在回调before_create 之前正在执行验证。您需要做的就是删除presence: true,因为您总是在创建新记录之前设置它。

【讨论】:

  • 那是另一种情况,即使我在rails控制台中尝试current_user.documents.create(name: 'some name')时没有验证,我每次都得到相同的密钥,这是主要问题。
猜你喜欢
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
  • 1970-01-01
相关资源
最近更新 更多