如何使用活动记录回调为轨道上的红宝石模型中的列添加动态值



我的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. 我将安全随机键逻辑移动到文档模型,如下所示:

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

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

但现在我的问题是,每当我打电话createnewkey价值总是相同的。但它应该在每次create调用之前随机生成。

在轨道控制台中

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

我做错了什么?

编辑:添加了宝石文件:

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

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

对于停留验证,我找到了另一个答案

# 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。享受。

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

最新更新