有一个关于如何设置移动设备的问题。如果你能给我一些建议,我将非常感激,这对我来说也是很有价值的一课,关于如何解决安装固定装置的问题。
不使用任何gems来设置fixture,只是在这种情况下使用默认的Rails方法。我有一个具有多个可翻译属性的Song模型,title
使用移动性,description
和content
使用移动性动作文本。
它工作得很好,但是当设置固定装置时,我发现很难将记录联系起来。这里有三个表songs
,其中使用的唯一字段是status。mobility_string_translations
存储title的翻译,action_text_rich_texts
存储description
s和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_type
是Song
而不是"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
存储任何翻译的title
s,以下可以添加到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
将从断点继续移动,并继续运行测试文件中的代码。
应该是这样!