Skip to content

Commit

Permalink
Add backend-specific translations generators
Browse files Browse the repository at this point in the history
  • Loading branch information
shioyama committed Mar 22, 2017
1 parent f43fa38 commit 9dbe4d2
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 3 deletions.
61 changes: 61 additions & 0 deletions lib/generators/rails/mobility/backend_generators/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen-string-literal: true
require "rails/generators/active_record/migration/migration_generator"

module Mobility
module BackendGenerators
class Base < ::Rails::Generators::NamedBase
argument :attributes, type: :array, default: []
include ::ActiveRecord::Generators::Migration

def create_migration_file
if self.class.migration_exists?(migration_dir, migration_file)
::Kernel.warn "Migration already exists: #{migration_file}"
else
migration_template "#{template}.rb", "db/migrate/#{migration_file}.rb"
end
end

def self.next_migration_number(dirname)
::ActiveRecord::Generators::Base.next_migration_number(dirname)
end

def backend
self.class.name.split('::').last.gsub(/Backend$/,'').underscore
end

protected

def attributes_with_index
attributes.select { |a| !a.reference? && a.has_index? }
end

private

def table_exists?
connection.table_exists?(table_name)
end

delegate :connection, to: ::ActiveRecord::Base

def truncate_index_name(index_name)
if index_name.size < connection.index_name_length
index_name
else
"index_#{Digest::SHA1.hexdigest(index_name)}"[0, connection.index_name_length].freeze
end
end

def template
"#{backend}_translations".freeze
end

def migration_dir
File.expand_path("db/migrate".freeze)
end

def migration_file
"create_#{file_name}_#{attributes.map(&:name).join('_and_')}_translations_for_mobility_#{backend}_backend".freeze
end
end
end
end
23 changes: 23 additions & 0 deletions lib/generators/rails/mobility/backend_generators/column_backend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class ColumnBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)

def initialize(*args)
super
unless table_exists?
raise NoTableDefined, "The table #{table_name} does not exist. Create it first before generating translated columns."
end
unless I18n.available_locales.present?
raise NoAvailableLocales, "You must set I18n.available_locales to use the column backend generator."
end
end
end

class NoTableDefined < StandardError; end
class NoAvailableLocales < StandardError; end
end
end
10 changes: 10 additions & 0 deletions lib/generators/rails/mobility/backend_generators/hstore_backend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class HstoreBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)
end
end
end
10 changes: 10 additions & 0 deletions lib/generators/rails/mobility/backend_generators/jsonb_backend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class JsonbBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class KeyValueBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class SerializedBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)
end
end
end
42 changes: 42 additions & 0 deletions lib/generators/rails/mobility/backend_generators/table_backend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen-string-literal: true
require "rails/generators"

module Mobility
module BackendGenerators
class TableBackend < Mobility::BackendGenerators::Base
source_root File.expand_path("../../templates", __FILE__)

def create_migration_file
if table_exists? && !self.class.migration_exists?(migration_dir, migration_file)
migration_template "#{backend}_migration.rb", "db/migrate/#{migration_file}.rb"
else
super
end
end

private

alias_method :model_table_name, :table_name
def table_name
model_table_name = super
"#{model_table_name.singularize}_translations"
end

def foreign_key
"#{model_table_name.singularize}_id"
end

def translation_index_name
truncate_index_name("index_#{table_name}_on_#{foreign_key}")
end

def translation_locale_index_name
truncate_index_name("index_#{table_name}_on_locale")
end

def translation_unique_index_name
truncate_index_name("index_#{table_name}_on_#{foreign_key}_and_locale")
end
end
end
end
5 changes: 5 additions & 0 deletions lib/generators/rails/mobility/generators.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require "rails/generators"

require_relative "./install_generator"
require_relative "./translations_generator"
require_relative "./backend_generators/base"
17 changes: 17 additions & 0 deletions lib/generators/rails/mobility/templates/column_translations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
def change
<% attributes.each do |attribute| -%>
<% I18n.available_locales.each do |locale| -%>
<% column_name = Mobility.normalize_locale_accessor(attribute.name, locale) -%>
<% if connection.column_exists?(table_name, column_name) -%>
<% warn "#{column_name} already exists, skipping." %>
<% else -%>
add_column :<%= table_name %>, :<%= column_name %>, :<%= attribute.type %><%= attribute.inject_options %>
<%- if attribute.has_index? -%>
add_index :<%= table_name %>, :<%= column_name %><%= attribute.inject_index_options %>
<%- end -%>
<% end -%>
<% end -%>
<% end -%>
end
end
17 changes: 17 additions & 0 deletions lib/generators/rails/mobility/templates/table_migration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
def change
<% attributes.each do |attribute| -%>
<%- if attribute.reference? -%>
add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
<%- elsif attribute.token? -%>
add_column :<%= table_name %>, :<%= attribute.name %>, :string<%= attribute.inject_options %>
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
<%- else -%>
add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
<%- if attribute.has_index? -%>
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
<%- end -%>
<%- end -%>
<% end -%>
end
end
28 changes: 28 additions & 0 deletions lib/generators/rails/mobility/templates/table_translations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
def change
create_table :<%= table_name %><%= primary_key_type %> do |t|
# Translated attribute(s)
<% attributes.each do |attribute| -%>
<% if attribute.token? -%>
t.string :<%= attribute.name %><%= attribute.inject_options %>
<% else -%>
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
<% end -%>
<% end -%>
t.string :locale, null: false
t.integer :<%= foreign_key %>, null: false
t.timestamps null: false
end
add_index :<%= table_name %>, :<%= foreign_key %>, name: :<%= translation_index_name %>
add_index :<%= table_name %>, :locale, name: :<%= translation_locale_index_name %>
add_index :<%= table_name %>, [:<%= foreign_key %>, :locale], name: :<%= translation_unique_index_name %>, unique: true
<%- attributes_with_index.each do |attribute| -%>
add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
<%- end -%>
end
end
37 changes: 37 additions & 0 deletions lib/generators/rails/mobility/translations_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen-string-literal: true

module Mobility
class TranslationsGenerator < ::Rails::Generators::NamedBase
BACKENDS = %w[column key_value hstore jsonb serialized table]
BACKEND_OPTIONS = { type: :string, desc: "Backend to use for translations (defaults to Mobility.default_backend)".freeze }
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"

class_option(:backend, BACKEND_OPTIONS)
invoke_from_option :backend

def self.class_options(options = nil)
super
@class_options[:backend] = Thor::Option.new(:backend, BACKEND_OPTIONS.merge(default: Mobility.default_backend.to_s.freeze))
@class_options
end

def self.prepare_for_invocation(name, value)
if name == :backend
require_relative "./backend_generators/#{value}_backend".freeze
Mobility::BackendGenerators.const_get("#{value}_backend".camelcase.freeze)
else
super
end
end

protected

def say_status(status, message, *args)
if status == :invoke && BACKENDS.include?(message)
super(status, "#{message}_backend".freeze, *args)
else
super
end
end
end
end
2 changes: 1 addition & 1 deletion lib/mobility/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def define_locale_accessors(attribute, locales)

def get_backend_class(backend: nil, model_class: nil)
raise Mobility::BackendRequired, "Backend option required if Mobility.config.default_backend is not set." if backend.nil?
klass = Module === backend ? backend : Mobility::Backend.const_get(backend.to_s.camelize.gsub(/\s+/, ''))
klass = Module === backend ? backend : Mobility::Backend.const_get(backend.to_s.camelize.gsub(/\s+/, ''.freeze).freeze)
model_class.nil? ? klass : klass.for(model_class)
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/mobility/rails.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
require "rails/generators"
require_relative "../generators/rails/mobility/install_generator"
require_relative "../generators/rails/mobility/generators"

0 comments on commit 9dbe4d2

Please sign in to comment.