From 8e5806f96c40452200de45dd90a37adef3c5d9a1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 3 Feb 2015 18:08:40 +0000 Subject: [PATCH] Fix translating Public Body Headings Fixes submission of form containing both existing and new translations --- .../admin_public_body_headings_controller.rb | 6 + app/models/public_body_heading.rb | 22 +++- .../admin_public_body_headings/_form.html.erb | 47 +++----- .../_locale_fields.html.erb | 9 ++ ...in_public_body_headings_controller_spec.rb | 105 +++++++++++++++++- .../admin_public_body_heading_edit_spec.rb | 58 ++++++++++ spec/models/public_body_heading_spec.rb | 58 ++++++++++ 7 files changed, 267 insertions(+), 38 deletions(-) create mode 100644 app/views/admin_public_body_headings/_locale_fields.html.erb create mode 100644 spec/integration/admin_public_body_heading_edit_spec.rb diff --git a/app/controllers/admin_public_body_headings_controller.rb b/app/controllers/admin_public_body_headings_controller.rb index e893e760d27..8e0f027d6fe 100644 --- a/app/controllers/admin_public_body_headings_controller.rb +++ b/app/controllers/admin_public_body_headings_controller.rb @@ -2,6 +2,9 @@ class AdminPublicBodyHeadingsController < AdminController def edit @heading = PublicBodyHeading.find(params[:id]) + I18n.available_locales.each do |locale| + @heading.translations.find_or_initialize_by_locale(locale) + end render :formats => [:html] end @@ -37,6 +40,9 @@ def reorder_categories def new @heading = PublicBodyHeading.new + I18n.available_locales.each do |locale| + @heading.translations.build(:locale => locale) + end render :formats => [:html] end diff --git a/app/models/public_body_heading.rb b/app/models/public_body_heading.rb index f394c37c6bd..060abecb616 100644 --- a/app/models/public_body_heading.rb +++ b/app/models/public_body_heading.rb @@ -7,13 +7,15 @@ # class PublicBodyHeading < ActiveRecord::Base - attr_accessible :name, :display_order, :translated_versions + attr_accessible :name, :display_order, :translated_versions, + :translations_attributes has_many :public_body_category_links, :dependent => :destroy has_many :public_body_categories, :order => :category_display_order, :through => :public_body_category_links default_scope order('display_order ASC') translates :name + accepts_nested_attributes_for :translations validates_uniqueness_of :name, :message => 'Name is already taken' validates_presence_of :name, :message => 'Name can\'t be blank' @@ -35,12 +37,11 @@ def translated_versions translations end - def translated_versions=(translation_attrs) + def translations_attributes=(translation_attrs) def empty_translation?(attrs) - attrs_with_values = attrs.select{ |key, value| value != '' and key != 'locale' } + attrs_with_values = attrs.select{ |key, value| value != '' and key.to_s != 'locale' } attrs_with_values.empty? end - if translation_attrs.respond_to? :each_value # Hash => updating translation_attrs.each_value do |attrs| next if empty_translation?(attrs) @@ -49,6 +50,12 @@ def empty_translation?(attrs) t.save! end else # Array => creating + warn "[DEPRECATION] PublicBodyHeading#translations_attributes= " \ + "will no longer accept an Array as of release 0.22. " \ + "Use Hash arguments instead. See " \ + "spec/models/public_body_heading_spec.rb and " \ + "app/views/admin_public_body_headings/_form.html.erb for more " \ + "details." translation_attrs.each do |attrs| next if empty_translation?(attrs) new_translation = PublicBodyHeading::Translation.new(attrs) @@ -57,6 +64,13 @@ def empty_translation?(attrs) end end + def translated_versions=(translation_attrs) + warn "[DEPRECATION] PublicBodyHeading#translated_versions= will be replaced " \ + "by PublicBodyHeading#translations_attributes= as of release 0.22" + self.translations_attributes = translation_attrs + end + + def add_category(category) unless public_body_categories.include?(category) public_body_categories << category diff --git a/app/views/admin_public_body_headings/_form.html.erb b/app/views/admin_public_body_headings/_form.html.erb index d4e914ca114..1ad31f3e0c9 100644 --- a/app/views/admin_public_body_headings/_form.html.erb +++ b/app/views/admin_public_body_headings/_form.html.erb @@ -4,37 +4,26 @@
-<% - for locale in I18n.available_locales do - if locale==I18n.default_locale # The default locale is submitted as part of the bigger object... - prefix = 'public_body_heading' - object = @heading - else # ...but additional locales go "on the side" - prefix = "public_body_heading[translated_versions][]" - object = @heading.new_record? ? - PublicBodyHeading::Translation.new : - @heading.find_translation_by_locale(locale.to_s) || PublicBodyHeading::Translation.new - end -%> - <%= fields_for prefix, object do |t| %> -
-
- <%= t.hidden_field :locale, :value => locale.to_s %> - -
- <%= t.text_field :name, :id => form_tag_id(t.object_name, :name, locale), :class => "span4" %> -
-
-
- <% - end -end -%> + <% @heading.translations.each do |translation| %> + <% if translation.locale.to_s == I18n.default_locale.to_s %> + <%= fields_for 'public_body_heading', @heading do |t| %> + <%= render :partial => 'locale_fields', :locals => { :t => t, :locale => translation.locale } %> + <% end %> + <% else %> + <%= f.fields_for(:translations, translation, :child_index => translation.locale) do |t| %> + <%= render :partial => 'locale_fields', :locals => { :t => t, :locale => translation.locale } %> + <% end %> + <% end %> + <% end %>
diff --git a/app/views/admin_public_body_headings/_locale_fields.html.erb b/app/views/admin_public_body_headings/_locale_fields.html.erb new file mode 100644 index 00000000000..3846bfafaf4 --- /dev/null +++ b/app/views/admin_public_body_headings/_locale_fields.html.erb @@ -0,0 +1,9 @@ +
+
+ <%= t.hidden_field :locale, :value => locale.to_s %> + +
+ <%= t.text_field :name, :id => form_tag_id(t.object_name, :name, locale), :class => "span4" %> +
+
+
diff --git a/spec/controllers/admin_public_body_headings_controller_spec.rb b/spec/controllers/admin_public_body_headings_controller_spec.rb index afbe0fa30d2..5cb166edc60 100644 --- a/spec/controllers/admin_public_body_headings_controller_spec.rb +++ b/spec/controllers/admin_public_body_headings_controller_spec.rb @@ -8,6 +8,15 @@ assigns[:heading].should be_a(PublicBodyHeading) end + it "builds new translations for all locales" do + get :new + + translations = assigns[:heading].translations.map{ |t| t.locale.to_s }.sort + available = I18n.available_locales.map{ |l| l.to_s }.sort + + expect(translations).to eq(available) + end + it 'renders the new template' do get :new expect(response).to render_template('new') @@ -33,8 +42,10 @@ post :create, { :public_body_heading => { :name => 'New Heading', - :translated_versions => [{ :locale => "es", - :name => "Mi Nuevo Heading" }] + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Mi Nuevo Heading" } + } } } PublicBodyHeading.count.should == n + 1 @@ -70,6 +81,11 @@ expect(assigns[:heading]).to eq(@heading) end + it "builds new translations if the body does not already have a translation in the specified locale" do + get :edit, :id => @heading.id + expect(assigns[:heading].translations.map(&:locale)).to include(:fr) + end + it "renders the edit template" do get :edit, :id => @heading.id expect(assigns[:heading]).to render_template('edit') @@ -96,9 +112,9 @@ :id => @heading.id, :public_body_heading => { :name => @name, - :translated_versions => { - @heading.id => {:locale => "es", - :name => "Renamed"} + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Renamed" } } } } @@ -114,6 +130,85 @@ end end + it 'adds a new translation' do + put :update, { + :id => @heading.id, + :public_body_heading => { + :name => @heading.name, + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Example Public Body Heading ES"} + } + } + } + + request.flash[:notice].should include('successful') + + pbh = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(pbh.name).to eq('Example Public Body Heading ES') + end + end + + it 'adds new translations' do + post :update, { + :id => @heading.id, + :public_body_heading => { + :name => @heading.name, + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Example Public Body Heading ES" }, + 'fr' => { :locale => "fr", + :name => "Example Public Body Heading FR" }, + } + } + } + + request.flash[:notice].should include('successful') + + pbh = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(pbh.name).to eq('Example Public Body Heading ES') + end + I18n.with_locale(:fr) do + expect(pbh.name).to eq('Example Public Body Heading FR') + end + end + + it 'updates an existing translation and adds a third translation' do + @heading.translations.create(:locale => 'es', + :name => 'Example Public Body Heading ES') + @heading.reload + + post :update, { + :id => @heading.id, + :public_body_heading => { + :name => @heading.name, + :translations_attributes => { + # Update existing translation + 'es' => { :locale => "es", + :name => "Renamed Example Public Body Heading ES" }, + # Add new translation + 'fr' => { :locale => "fr", + :name => "Example Public Body Heading FR" } + } + } + } + + request.flash[:notice].should include('successful') + + pbh = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(pbh.name).to eq('Renamed Example Public Body Heading ES') + end + I18n.with_locale(:fr) do + expect(pbh.name).to eq('Example Public Body Heading FR') + end + end + it "redirects to the edit page after a successful update" do post :update, { :id => @heading.id, :public_body_heading => { :name => "Renamed" } } diff --git a/spec/integration/admin_public_body_heading_edit_spec.rb b/spec/integration/admin_public_body_heading_edit_spec.rb new file mode 100644 index 00000000000..cc7b7bbede5 --- /dev/null +++ b/spec/integration/admin_public_body_heading_edit_spec.rb @@ -0,0 +1,58 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +require File.expand_path(File.dirname(__FILE__) + '/alaveteli_dsl') + +describe 'Editing a Public Body Heading' do + before do + AlaveteliConfiguration.stub!(:skip_admin_auth).and_return(false) + + confirm(:admin_user) + @admin = login(:admin_user) + @heading = FactoryGirl.create(:public_body_heading) + end + + it 'can edit the default locale' do + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_name__en', :with => 'New Heading EN' + @admin.click_button 'Save' + + @heading.reload + expect(@heading.name).to eq('New Heading EN') + end + + it 'can add a translation for a single locale' do + expect(@heading.find_translation_by_locale('fr')).to be_nil + + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_fr_name__fr', :with => 'New Heading FR' + @admin.click_button 'Save' + + @heading.reload + I18n.with_locale(:fr) do + expect(@heading.name).to eq('New Heading FR') + end + end + + it 'can add a translation for multiple locales' do + # Add FR translation + expect(@heading.find_translation_by_locale('fr')).to be_nil + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_fr_name__fr', :with => 'New Heading FR' + @admin.click_button 'Save' + + # Add ES translation + expect(@heading.find_translation_by_locale('es')).to be_nil + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_es_name__es', :with => 'New Heading ES' + @admin.click_button 'Save' + + @heading.reload + I18n.with_locale(:fr) do + expect(@heading.name).to eq('New Heading FR') + end + + I18n.with_locale(:es) do + expect(@heading.name).to eq('New Heading ES') + end + end + +end \ No newline at end of file diff --git a/spec/models/public_body_heading_spec.rb b/spec/models/public_body_heading_spec.rb index 9372e0a07fe..61649ccaa28 100644 --- a/spec/models/public_body_heading_spec.rb +++ b/spec/models/public_body_heading_spec.rb @@ -63,4 +63,62 @@ PublicBodyHeading.next_display_order.should == 1 end end + + describe :translations_attributes= do + + context 'translation_attrs is a Hash' do + + it 'takes the correct code path for a Hash' do + attrs = {} + attrs.should_receive(:each_value) + PublicBodyHeading.new().translations_attributes = attrs + end + + it 'updates an existing translation' do + heading = FactoryGirl.create(:public_body_heading) + params = { 'es' => { :locale => 'es', + :name => 'Renamed' } } + + heading.translations_attributes = params + I18n.with_locale(:es) { expect(heading.name).to eq('Renamed') } + end + + it 'updates an existing translation and creates a new translation' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations.create(:locale => 'es', + :name => 'Los Heading') + + expect(heading.translations.size).to eq(2) + + heading.translations_attributes = { + 'es' => { :locale => 'es', + :name => 'Renamed' }, + 'fr' => { :locale => 'fr', + :name => 'Le Heading' } + } + + expect(heading.translations.size).to eq(3) + I18n.with_locale(:es) { expect(heading.name).to eq('Renamed') } + I18n.with_locale(:fr) { expect(heading.name).to eq('Le Heading') } + end + + it 'skips empty translations' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations.create(:locale => 'es', + :name => 'Los Heading') + + expect(heading.translations.size).to eq(2) + + heading.translations_attributes = { + 'es' => { :locale => 'es', + :name => 'Los Heading' }, + 'fr' => { :locale => 'fr' } + } + + expect(heading.translations.size).to eq(2) + end + + end + end + end