Make answers translatable

This commit is contained in:
Julian Herrero
2018-09-20 17:13:40 +02:00
parent 5e6248d2ac
commit 673ec075eb
13 changed files with 258 additions and 28 deletions

View File

@@ -23,7 +23,10 @@ App.Globalize =
element.addClass('is-active'); element.addClass('is-active');
remove_language: (locale) -> remove_language: (locale) ->
$(".js-globalize-attribute[data-locale=" + locale + "]").val('').hide() $(".js-globalize-attribute[data-locale=" + locale + "]").each ->
$(this).val('').hide()
if CKEDITOR.instances[$(this).attr('id')]
CKEDITOR.instances[$(this).attr('id')].setData('')
$(".js-globalize-locale-link[data-locale=" + locale + "]").hide() $(".js-globalize-locale-link[data-locale=" + locale + "]").hide()
next = $(".js-globalize-locale-link:visible").first() next = $(".js-globalize-locale-link:visible").first()
App.Globalize.highlight_locale(next) App.Globalize.highlight_locale(next)

View File

@@ -1,4 +1,6 @@
class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
include Translatable
before_action :load_answer, only: [:show, :edit, :update, :documents] before_action :load_answer, only: [:show, :edit, :update, :documents]
load_and_authorize_resource :question, class: "::Poll::Question" load_and_authorize_resource :question, class: "::Poll::Question"
@@ -49,11 +51,15 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
def answer_params def answer_params
documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
attributes = [:title, :description, :question_id, documents_attributes: documents_attributes] attributes = [:title, :description, :question_id, documents_attributes: documents_attributes]
params.require(:poll_question_answer).permit(*attributes) params.require(:poll_question_answer).permit(*attributes, *translation_params(Poll::Question::Answer))
end end
def load_answer def load_answer
@answer = ::Poll::Question::Answer.find(params[:id] || params[:answer_id]) @answer = ::Poll::Question::Answer.find(params[:id] || params[:answer_id])
end end
def resource
load_answer unless @answer
@answer
end
end end

View File

@@ -9,7 +9,9 @@ class Poll::Answer < ActiveRecord::Base
validates :author, presence: true validates :author, presence: true
validates :answer, presence: true validates :answer, presence: true
validates :answer, inclusion: { in: ->(a) { a.question.question_answers.pluck(:title) }}, validates :answer, inclusion: { in: ->(a) { a.question.question_answers
.joins(:translations)
.pluck("poll_question_answer_translations.title") }},
unless: ->(a) { a.question.blank? } unless: ->(a) { a.question.blank? }
scope :by_author, ->(author_id) { where(author_id: author_id) } scope :by_author, ->(author_id) { where(author_id: author_id) }

View File

@@ -10,7 +10,9 @@ class Poll::PartialResult < ActiveRecord::Base
validates :question, presence: true validates :question, presence: true
validates :author, presence: true validates :author, presence: true
validates :answer, presence: true validates :answer, presence: true
validates :answer, inclusion: { in: ->(a) { a.question.question_answers.pluck(:title) }}, validates :answer, inclusion: { in: ->(a) { a.question.question_answers
.joins(:translations)
.pluck("poll_question_answer_translations.title") }},
unless: ->(a) { a.question.blank? } unless: ->(a) { a.question.blank? }
validates :origin, inclusion: { in: VALID_ORIGINS } validates :origin, inclusion: { in: VALID_ORIGINS }

View File

@@ -1,6 +1,11 @@
class Poll::Question::Answer < ActiveRecord::Base class Poll::Question::Answer < ActiveRecord::Base
include Galleryable include Galleryable
include Documentable include Documentable
translates :title, touch: true
translates :description, touch: true
globalize_accessors locales: [:en, :es, :fr, :nl, :pt_br]
documentable max_documents_allowed: 3, documentable max_documents_allowed: 3,
max_file_size: 3.megabytes, max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ] accepted_content_types: [ "application/pdf" ]
@@ -15,7 +20,7 @@ class Poll::Question::Answer < ActiveRecord::Base
before_validation :set_order, on: :create before_validation :set_order, on: :create
def description def description
super.try :html_safe self[:description].try :html_safe
end end
def self.order_answers(ordered_array) def self.order_answers(ordered_array)

View File

@@ -1,15 +1,30 @@
<%= form_for(@answer, url: form_url) do |f| %> <%= render "admin/shared/globalize_locales", resource: @answer %>
<%= translatable_form_for(@answer, url: form_url) do |f| %>
<%= render 'shared/errors', resource: @answer %> <%= render 'shared/errors', resource: @answer %>
<%= f.hidden_field :question_id, value: @answer.question_id || @question.id %> <%= f.hidden_field :question_id, value: @answer.question_id || @question.id %>
<%= f.text_field :title %> <%= f.translatable_text_field :title %>
<div class="ckeditor"> <div class="ckeditor">
<%= f.cktext_area :description, <%= f.label :description, t("admin.shared.description") %>
<% @answer.globalize_locales.each do |locale| %>
<% globalize(locale) do %>
<%= content_tag :span, class: "js-globalize-attribute",
data: { locale: locale },
style: display_translation?(locale) do %>
<%= f.cktext_area "description_#{locale}",
maxlength: Poll::Question.description_max_length, maxlength: Poll::Question.description_max_length,
ckeditor: { language: I18n.locale } %> ckeditor: { language: locale },
class: "js-globalize-attribute",
data: { locale: locale },
label: false %>
<% end %>
<% end %>
<% end %>
</div> </div>
<div class="small-12 medium-4 large-2 margin-top"> <div class="small-12 medium-4 large-2 margin-top">

View File

@@ -60,9 +60,17 @@ section "Creating Poll Questions & Answers" do
question.save! question.save!
Faker::Lorem.words((2..4).to_a.sample).each do |title| Faker::Lorem.words((2..4).to_a.sample).each do |title|
description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>" description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>"
Poll::Question::Answer.create!(question: question, answer = Poll::Question::Answer.new(question: question,
title: answer.capitalize, title: title.capitalize,
description: description) description: description)
I18n.available_locales.map do |locale|
neutral_locale = locale.to_s.downcase.underscore.to_sym
Globalize.with_locale(neutral_locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
end
end
answer.save!
end end
end end
end end
@@ -196,10 +204,19 @@ section "Creating Poll Questions from Proposals" do
proposal = Proposal.all.sample proposal = Proposal.all.sample
poll = Poll.current.first poll = Poll.current.first
question = Poll::Question.create(poll: poll) question = Poll::Question.create(poll: poll)
Faker::Lorem.words((2..4).to_a.sample).each do |answer| Faker::Lorem.words((2..4).to_a.sample).each do |title|
Poll::Question::Answer.create!(question: question, description = "<p>#{Faker::ChuckNorris.fact}</p>"
title: answer.capitalize, answer = Poll::Question::Answer.new(question: question,
description: Faker::ChuckNorris.fact) title: title.capitalize,
description: description)
I18n.available_locales.map do |locale|
neutral_locale = locale.to_s.downcase.underscore.to_sym
Globalize.with_locale(neutral_locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
end
end
answer.save!
end end
question.copy_attributes_from_proposal(proposal) question.copy_attributes_from_proposal(proposal)
title = question.title title = question.title
@@ -218,10 +235,19 @@ section "Creating Successful Proposals" do
proposal = Proposal.all.sample proposal = Proposal.all.sample
poll = Poll.current.first poll = Poll.current.first
question = Poll::Question.create(poll: poll) question = Poll::Question.create(poll: poll)
Faker::Lorem.words((2..4).to_a.sample).each do |answer| Faker::Lorem.words((2..4).to_a.sample).each do |title|
Poll::Question::Answer.create!(question: question, description = "<p>#{Faker::ChuckNorris.fact}</p>"
title: answer.capitalize, answer = Poll::Question::Answer.new(question: question,
description: Faker::ChuckNorris.fact) title: title.capitalize,
description: description)
I18n.available_locales.map do |locale|
neutral_locale = locale.to_s.downcase.underscore.to_sym
Globalize.with_locale(neutral_locale) do
answer.title = "#{title} (#{locale})"
answer.description = "#{description} (#{locale})"
end
end
answer.save!
end end
question.copy_attributes_from_proposal(proposal) question.copy_attributes_from_proposal(proposal)
title = question.title title = question.title

View File

@@ -0,0 +1,14 @@
class AddPollQuestionAnswerTranslations < ActiveRecord::Migration
def self.up
Poll::Question::Answer.create_translation_table!(
title: :string,
description: :text
)
end
def self.down
Poll::Question::Answer.drop_translation_table!
end
end

View File

@@ -829,6 +829,18 @@ ActiveRecord::Schema.define(version: 20180813141443) do
add_index "poll_partial_results", ["origin"], name: "index_poll_partial_results_on_origin", using: :btree add_index "poll_partial_results", ["origin"], name: "index_poll_partial_results_on_origin", using: :btree
add_index "poll_partial_results", ["question_id"], name: "index_poll_partial_results_on_question_id", using: :btree add_index "poll_partial_results", ["question_id"], name: "index_poll_partial_results_on_question_id", using: :btree
create_table "poll_question_answer_translations", force: :cascade do |t|
t.integer "poll_question_answer_id", null: false
t.string "locale", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "title"
t.text "description"
end
add_index "poll_question_answer_translations", ["locale"], name: "index_poll_question_answer_translations_on_locale", using: :btree
add_index "poll_question_answer_translations", ["poll_question_answer_id"], name: "index_85270fa85f62081a3a227186b4c95fe4f7fa94b9", using: :btree
create_table "poll_question_answer_videos", force: :cascade do |t| create_table "poll_question_answer_videos", force: :cascade do |t|
t.string "title" t.string "title"
t.string "url" t.string "url"

View File

@@ -15,8 +15,8 @@ feature 'Answers' do
visit admin_question_path(question) visit admin_question_path(question)
click_link 'Add answer' click_link 'Add answer'
fill_in 'poll_question_answer_title', with: title fill_in 'poll_question_answer_title_en', with: title
fill_in 'poll_question_answer_description', with: description fill_in 'poll_question_answer_description_en', with: description
click_button 'Save' click_button 'Save'
@@ -33,8 +33,8 @@ feature 'Answers' do
visit admin_question_path(question) visit admin_question_path(question)
click_link 'Add answer' click_link 'Add answer'
fill_in 'poll_question_answer_title', with: title fill_in 'poll_question_answer_title_en', with: title
fill_in 'poll_question_answer_description', with: description fill_in 'poll_question_answer_description_en', with: description
click_button 'Save' click_button 'Save'
@@ -53,7 +53,7 @@ feature 'Answers' do
old_title = answer.title old_title = answer.title
new_title = 'Ex Machina' new_title = 'Ex Machina'
fill_in 'poll_question_answer_title', with: new_title fill_in 'poll_question_answer_title_en', with: new_title
click_button 'Save' click_button 'Save'

View File

@@ -28,8 +28,8 @@ feature 'Answers' do
visit admin_question_path(question) visit admin_question_path(question)
click_link "Add answer" click_link "Add answer"
fill_in "poll_question_answer_title", with: "¿Would you like to reform Central Park?" fill_in "poll_question_answer_title_en", with: "¿Would you like to reform Central Park?"
fill_in "poll_question_answer_description", with: "Adding more trees, creating a play area..." fill_in "poll_question_answer_description_en", with: "Adding more trees, creating a play area..."
click_button "Save" click_button "Save"
expect(page).to have_content "Answer created successfully" expect(page).to have_content "Answer created successfully"

View File

@@ -0,0 +1,138 @@
# coding: utf-8
require 'rails_helper'
feature "Translations" do
context "Polls" do
let(:poll) { create(:poll, name_en: "Name in English",
name_es: "Nombre en Español",
summary_en: "Summary in English",
summary_es: "Resumen en Español",
description_en: "Description in English",
description_es: "Descripción en Español") }
background do
admin = create(:administrator)
login_as(admin.user)
end
context "Questions" do
let(:question) { create(:poll_question, poll: poll,
title_en: "Question in English",
title_es: "Pregunta en Español") }
context "Answers" do
let(:answer) { create(:poll_question_answer, question: question,
title_en: "Answer in English",
title_es: "Respuesta en Español",
description_en: "Description in English",
description_es: "Descripción en Español") }
before do
@edit_answer_url = edit_admin_answer_path(answer)
end
scenario "Add a translation", :js do
visit @edit_answer_url
select "Français", from: "translation_locale"
fill_in 'poll_question_answer_title_fr', with: 'Answer en Français'
fill_in_ckeditor 'poll_question_answer_description_fr', with: 'Description en Français'
click_button 'Save'
expect(page).to have_content "Changes saved"
expect(page).to have_content "Answer in English"
expect(page).to have_content "Description in English"
select('Español', from: 'locale-switcher')
expect(page).to have_content "Respuesta en Español"
expect(page).to have_content "Descripción en Español"
select('Français', from: 'locale-switcher')
expect(page).to have_content "Answer en Français"
expect(page).to have_content "Description en Français"
end
scenario "Update a translation", :js do
visit @edit_answer_url
click_link "Español"
fill_in 'poll_question_answer_title_es', with: 'Pregunta correcta en Español'
fill_in_ckeditor 'poll_question_answer_description_es', with: 'Descripción correcta en Español'
click_button 'Save'
expect(page).to have_content "Changes saved"
expect(page).to have_content("Answer in English")
expect(page).to have_content("Description in English")
select('Español', from: 'locale-switcher')
expect(page).to have_content("Pregunta correcta en Español")
expect(page).to have_content("Descripción correcta en Español")
end
scenario "Remove a translation", :js do
visit @edit_answer_url
click_link "Español"
click_link "Remove language"
expect(page).not_to have_link "Español"
click_button "Save"
visit @edit_answer_url
expect(page).not_to have_link "Español"
end
context "Globalize javascript interface" do
scenario "Highlight current locale", :js do
visit @edit_answer_url
expect(find("a.js-globalize-locale-link.is-active")).to have_content "English"
select('Español', from: 'locale-switcher')
expect(find("a.js-globalize-locale-link.is-active")).to have_content "Español"
end
scenario "Highlight selected locale", :js do
visit @edit_answer_url
expect(find("a.js-globalize-locale-link.is-active")).to have_content "English"
click_link "Español"
expect(find("a.js-globalize-locale-link.is-active")).to have_content "Español"
end
scenario "Show selected locale form", :js do
visit @edit_answer_url
expect(page).to have_field('poll_question_answer_title_en', with: 'Answer in English')
click_link "Español"
expect(page).to have_field('poll_question_answer_title_es', with: 'Respuesta en Español')
end
scenario "Select a locale and add it to the poll form", :js do
visit @edit_answer_url
select "Français", from: "translation_locale"
expect(page).to have_link "Français"
click_link "Français"
expect(page).to have_field('poll_question_answer_title_fr')
end
end
end
end
end
end

View File

@@ -0,0 +1,7 @@
def fill_in_ckeditor(id, with:)
within_frame find("#cke_#{id} iframe") do
find('body').base.send_keys with
end
end