如何在使用Key Value后端移动时设置fixture ?



有一个关于如何设置移动设备的问题。如果你能给我一些建议,我将非常感激,这对我来说也是很有价值的一课,关于如何解决安装固定装置的问题。

不使用任何gems来设置fixture,只是在这种情况下使用默认的Rails方法。我有一个具有多个可翻译属性的Song模型,title使用移动性,descriptioncontent使用移动性动作文本。

它工作得很好,但是当设置固定装置时,我发现很难将记录联系起来。这里有三个表songs,其中使用的唯一字段是status。mobility_string_translations存储title的翻译,action_text_rich_texts存储descriptions和content的翻译。

这是我的翻译设置看起来像在Song:

class Song < ApplicationRecord
extend Mobility
validates :title_pt, presence: true 
validates :status, inclusion: { in: %w(draft published private) },
presence: true
translates :title, type: :string, locale_accessors: I18n.available_locales
translates :description, backend: :action_text, locale_accessors: I18n.available_locales
translates :content, backend: :action_text, locale_accessors: I18n.available_locales
# file continuation...

对于fixturesongs.yml是这样的:

one:
status: "published"

然后根据我在网上找到的东西,我创建了mobility/string_translations.yml,内容如下:

one:
translatable_id: one (Song)
translatable_type: "Song"
key: "title"
value: "Title in English"
locale: "en"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
two:
translatable_id: one (Song)
translatable_type: "Song"
key: "title"
value: "Titulo em Português"
locale: "pt"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>

这似乎工作,但我知道它不是因为当我检查@song = songs(:one)寻找翻译值(@song.title_pt@song.title_en)他们都是nil。

你知道该怎么做吗?🙏

我认为问题在于您如何在mobility_string_translation表中声明translatable关系。

应该是完全显式的

translatable_id: 1
translatable_type: Song

或由fixture提供的简写。

translatable: one (Song)

你把两者都混在一起了。

多态belongs_tohttps://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html中记录了它。

由于某些原因,我已经设法使显式表单工作,但不是速记。

我一直在寻找关于如何使固定装置工作与机动性的说明,你提供了你的例子的繁重工作,所以非常感谢。

在我的情况下,问题是translatable_typeSong而不是"Song",它无法将mobility_string_translations中的记录映射到正确的Song记录。下面是我用来编写测试的设置的更多细节:

通过work我的意思是,在fixture文件中定义的Mobility转换记录被检测到,并且可以用来组成测试。运行@song.title_en应该输出一个值,而不是nil

让我们考虑下面的Song模型,它有一个可以翻译的title和一个仅用于影响前端歌曲可见性的status。一对Songs的fixture看起来像这样:

# test/fixtures/songs.yml
one:
id: 1
status: "published"
two:
id: 2
status: "draft"

id通常在fixture中不指定,但这里有必要这样做,以便我们确定在指向已翻译的记录时使用哪个标识符。

移动实现将在mobility_string_translations存储任何翻译的titles,以下可以添加到test/fixtures/mobility/string_translations.yml:

# test/fixtures/mobility/string_translations.yml
song_one_en:
translatable_id: 1
translatable_type: "Song"
key: "title"
value: "Maçaranduba Wood"
locale: "en"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
song_one_pt:
translatable_id: 1
translatable_type: "Song"
key: "title"
value: "Madeira de Maçaranduba"
locale: "pt"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
song_two_en:
translatable_id: 2
translatable_type: "Song"
key: "title"
value: "Dona Maria from Camboatá"
locale: "en"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
song_two_pt:
translatable_id: 2
translatable_type: "Song"
key: "title"
value: "Dona Maria do Camboatá"
locale: "pt"
created_at: <%= Time.now %>
updated_at: <%= Time.now %>

在这种情况下,每首歌都包含英语和葡萄牙语的标题,但是记录将要使用或需要测试的任何语言环境都可以包含在这里,在单个记录中。

这里重要的一点是所有translatable_type列都是显式的string类型。例如,在为属性添加值时,执行"Song",而不是Song

使用此方法设置fixture,将已转换的属性关联到一个记录,并使它们能够在测试中被访问。

例如,要更改歌曲的标题,可以将记录以setup块的形式带入测试,并且title的翻译将可用并且可以修改:

# test/controllers/song_controller_test.rb
require "test_helper"
class SongControllerTest < ActionDispatch::IntegrationTest
setup do
@song = songs(:one)
end
test "admin can edit a song" do
# Keeps a copy of the original record for comparison.
current_record = @song

# Passes the locale to the request helper to keep it from getting confused with the record id.
# Changes the title of the record.
patch song_url(I18n.locale, @song, { song: { title_en: 'Updated Song Title' } })

# Retrieves the same record to be used for comparison.
updated_record = Song.find(@song.id)

# Checks that a change actually occurred.
assert current_record.updated_at != updated_record.updated_at

# Checks that the list of songs is being displayed to the user.
assert_redirected_to songs_path
end
end

为了确保fixture已经在模型和翻译的记录之间建立了关联,可以使用debugger方法。首先将它作为一个断点添加到测试逻辑中,在这种情况下,我将使用上面的示例:

# test/controllers/song_controller_test.rb
test "admin can edit a song" do
current_record = @song  
patch song_url(I18n.locale, @song, { song: { title_en: 'Updated Song Title' } })
updated_record = Song.find(@song.id)

debugger # <-- The script will pause here.

assert current_record.updated_at != updated_record.updated_at
assert_redirected_to songs_path
end

然后可以运行测试,bin/rails test可以工作,但在本例中,仅运行此文件的测试的命令为:

bin/rails test test/controllers/role_controller_test.rb

终端中的输出将类似于以下内容,程序将在此时暂停,并且它是交互式的:

bin/rails test test/controllers/song_controller_test.rb
Running 26 tests in a single process (parallelization threshold is 50)
Run options: --seed 56548
# Running:
.............[64, 73] in ~/Projects/rails_app/test/controllers/song_controller_test.rb
64|
65| current_record = @song
66| patch song_url(I18n.locale, @song, { song: { title_en: 'Updated Song Title' } })
67| updated_record = Song.find(@song.id)
68|
=> 69| debugger # <-- The script will pause here.
70|
71| # Checks that a change actually occurred.
72| assert current_record.updated_at != updated_record.updated_at
73|
=>
#0 block in <class:SongControllerTest> at ~/Projects/rails_app/test/controllers/song_controller_test.rb:69
#1 block in run (3 levels) at ~/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/minitest-5.15.0/lib/minitest/test.rb:98
# and 24 frames (use `bt' command for all frames)
(rdbg)

任何在debugger之前定义的变量都可以被访问,这可以用来检查@song是否被更改:

(rdbg) @song.title_en    # ruby
"Updated Song Title"
(rdbg) @song.title_pt    # ruby
"Madeira de Maçaranduba"

使用测试用例中定义的patch请求更新标题。输入continue将从断点继续移动,并继续运行测试文件中的代码。

应该是这样!

最新更新