Giter Site home page Giter Site logo

multilang-hstore's Introduction

Multilang-hstore

Build Status

Multilang is a small translation library for translating database values for Active Support/Rails 4 using the Hstore datatype.

This project is a fork of artworklv/multilang with some remarkable differences:

  • Replaced YAML text fields in favor of Hstore fields.
  • The translation hash is no longer limited to locales in I18n.available_locales.
  • Support for Rails 3 and Rails 4.

Installation

Rails 3

The last version of the gem for the Rails 3 series is 0.4. You need configure the multilang gem inside your gemfile:

gem 'multilang-hstore'

Do not forget to run:

bundle install

Rails 4

Starting with version 1.0.0, this gem is intented to be used in Rails 4. If you are migrating an existing project from Rails 3, make sure you read Migrating to Rails 4.

You need configure the multilang gem inside your gemfile:

gem 'multilang-hstore', '~> 1.0.0'

Do not forget to run:

bundle install

Basic Usage

This is a walkthrough with all steps you need to setup multilang translated attributes, including model and migration.

We're assuming here you want a Post model with some multilang attributes, as outlined below:

class Post < ActiveRecord::Base
  multilang :title
end

or

class Post < ActiveRecord::Base
  multilang :title, :description, :required => true, :length => 100
end

The multilang translations are stored in the same model attributes (eg. title):

You may need to create migration for Post as usual, but multilang attributes should be in hstore type:

create_table(:posts) do |t|
  t.hstore :title
  t.timestamps
end

Thats it!

Now you are able to translate values for the attributes :title and :description per locale:

I18n.locale = :en
post.title = 'Multilang rocks!'
I18n.locale = :lv
post.title = 'Multilang rulle!'

I18n.locale = :en
post.title #=> Multilang rocks!
I18n.locale = :lv
post.title #=> Multilang rulle!

You may assign attributes through auto generated methods (this methods depend from I18n.available_locales):

I18n.available_locales #=> [:en. :lv]

post.title_en = 'Multilang rocks!'
post.title_lv = 'Multilang rulle!'

post.title_en #=>  'Multilang rocks!'
post.title_lv #=>  'Multilang rulle!'

You may use initialization if needed:

Post.new(:title => {:en => 'Multilang rocks!', :lv => 'Multilang rulle!'})

or

Post.new(:title_en => 'Multilang rocks!', :title_lv => 'Multilang rulle!')

Also, you may ise same hashes with setters:

post.title = {:en => 'Multilang rocks!', :lv => 'Multilang rulle!'} 

Attribute methods

You may get other translations via attribute translation method:

post.title.translation[:lv] #=> 'Multilang rocks!'
post.title.translation[:en] #=> 'Multilang rulle!'
post.title.translation.locales #=> [:en, :lv]

If you have incomplete translations, you can get translation from other locale:

post.title = {:en => 'Multilang rocks!', :lv => ''}
I18n.locale = :lv
post.title.any #=> 'Multilang rocks!'

The value from "any" method returns value for I18n.current_locale or, if value is empty, return value for I18n.default_locale, if it's empty too it searches through all locales. It takes searching order from I18n.available_locales array. If you don't need ANY value, you can also use current_or_default method like post.title.current_or_default (it searches value for current and default locales only).

Validations

Multilang has some validation features:

multilang :title, :length => 100  #define maximal length validator
multilang :title, :required => true #define requirement validator for all available_locales
multilang :title, :required => 1 #define requirement validator for 1 locale
multilang :title, :required => [:en, :es] #define requirement validator for specific locales
multilang :title, :format => /regexp/ #define validates_format_of validator

Tests

Test runs using a temporary database in your local PostgreSQL server:

Create a test database:

$ createdb multilang-hstore-test

Create the hstore extension:

psql -d multilang-hstore-test -c "CREATE EXTENSION IF NOT EXISTS hstore"

Create the role postgres if necessary:

$ createuser -s -r postgres 

Finally, you can run your tests:

rspec	

Migrating to Rails 4

Migrating to Rails 4 and multilang-hstore 1.x is a very straightforward process.

Deprecated Dependencies

Rails 4 has built-in support for hstore datatype, so using any dependency to activerecord-postgres-hstore must be removed from your Gemfile:

Mass-Assignment

Mass-assignment was deprecated in Rails 4, so it was in our gem. You will receive an error similar to this:

Multilang::Exceptions::DeprecationError: :accessible was deprecated starting multilang-hstore >= 1.0.0 which is intended for Rails >= 4.0.0. Check more info about the deprecation of mass-asignment in Rails 4

This basically means you are trying to use the option :accessible which is deprecated. Removing the option will solve the issue:

Before:

class Post < ActiveRecord::Base
  multilang :title, :accessible=>true
end

After:

class Post < ActiveRecord::Base
  multilang :title
end

Bugs and Feedback

Use http://github.com/bithavoc/multilang-hstore/issues

License(MIT)

  • Copyright (c) 2012 - 2014 Bithavoc and Contributors - http://bithavoc.io
  • Copyright (c) 2010 Arthur Meinart

multilang-hstore's People

Contributors

artworklv avatar bithavoc avatar guilleiguaran avatar jerrygreen avatar johanfirebase avatar kogre avatar proalexandr avatar tih-ra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

multilang-hstore's Issues

Compatability issue with Rails-4.0.0.rc2

The gem works great under Rails 4.0.0.rc1. For example:

Loading development environment (Rails 4.0.0.rc1)
irb(main):001:0> a = Announcement.first
  Announcement Load (3.1ms)  SELECT "announcements".* FROM "announcements" ORDER BY "announcements"."id" DESC LIMIT 1
=> #<Announcement id: 1, app_id: 1, title: {"en"=>"Title"}, message: {}, image: nil, link: nil, status: 0, created_at: "2013-06-25 03:44:19", updated_at: "2013-06-25 03:44:19">

But I'm getting the following error under Rails 4.0.0.rc2:

Loading development environment (Rails 4.0.0.rc2)
irb(main):001:0> a = Announcement.first
  Announcement Load (2.0ms)  SELECT "announcements".* FROM "announcements" ORDER BY "announcements"."id" DESC LIMIT 1
(Object doesn't support #inspect)
=> 

Active record query by string

Having set multilang :titleon the item model, with quite a standard query :
Item.where("title = ?", 'string')

I get the following :

ActiveRecord::StatementInvalid: PG::InternalError: ERROR:  Unexpected end of string
LINE 1: SELECT "items".* FROM "items" WHERE (title = 'string') ORDER ...

Can I believe this is due to the multilang/hstore settings ? What can be done do use this type of query ?

NoMethodError: undefined method `read' for {"en"=>"Gründerblog"}:Hash

Similar to the other bug I reported earlier (#12), I sometimes also get this error message:

/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:70 in read
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:43 in []
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/active_record_extensions.rb:55 in block (3 levels) in multilang
app/models/social_networks/facebook/page.rb:35 in search_data
/gems/searchkick-0.9.0/lib/searchkick/index.rb:495 in search_data
/gems/searchkick-0.9.0/lib/searchkick/index.rb:48 in store
/gems/searchkick-0.9.0/lib/searchkick/logging.rb:24 in block in store_with_instrumentation
/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in block in instrument
/gems/activesupport-4.2.4/lib/active_support/notifications/instrumenter.rb:20 in instrument
/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in instrument
/gems/searchkick-0.9.0/lib/searchkick/logging.rb:23 in store_with_instrumentation
/gems/searchkick-0.9.0/lib/searchkick/reindex_v2_job.rb:19 in perform
/gems/activejob-4.2.4/lib/active_job/execution.rb:32 in block in perform_now
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:117 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:117 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:555 in block (2 levels) in compile
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:498 in block (2 levels) in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in block (2 levels) in simple
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/active_job.rb:46 in call
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/active_job.rb:46 in perform
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/active_job.rb:20 in block (3 levels) in <top (required)>
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in instance_exec
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in block in make_lambda
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in block in simple
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in block in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:498 in block (2 levels) in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in block (2 levels) in simple
/gems/i18n-0.7.0/lib/i18n.rb:257 in with_locale
/gems/activejob-4.2.4/lib/active_job/translation.rb:7 in block (2 levels) in <module:Translation>
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in instance_exec
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in block in make_lambda
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in block in simple
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in block in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:498 in block (2 levels) in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:343 in block (2 levels) in simple
/gems/activejob-4.2.4/lib/active_job/logging.rb:23 in call
/gems/activejob-4.2.4/lib/active_job/logging.rb:23 in block (4 levels) in <module:Logging>
/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in block in instrument
/gems/activesupport-4.2.4/lib/active_support/notifications/instrumenter.rb:20 in instrument
/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in instrument
/gems/activejob-4.2.4/lib/active_job/logging.rb:22 in block (3 levels) in <module:Logging>
/gems/activejob-4.2.4/lib/active_job/logging.rb:43 in block in tag_logger
/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:68 in block in tagged
/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:26 in tagged
/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:68 in tagged
/gems/activejob-4.2.4/lib/active_job/logging.rb:43 in tag_logger
/gems/activejob-4.2.4/lib/active_job/logging.rb:19 in block (2 levels) in <module:Logging>
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in instance_exec
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:441 in block in make_lambda
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:342 in block in simple
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:497 in block in around
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:505 in call
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:92 in __run_callbacks__
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:778 in _run_perform_callbacks
/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:81 in run_callbacks
/gems/activejob-4.2.4/lib/active_job/execution.rb:31 in perform_now
/gems/activejob-4.2.4/lib/active_job/execution.rb:21 in execute
/gems/activejob-4.2.4/lib/active_job/queue_adapters/sidekiq_adapter.rb:42 in perform
/gems/sidekiq-3.5.0/lib/sidekiq/processor.rb:75 in execute_job
/gems/sidekiq-3.5.0/lib/sidekiq/processor.rb:52 in block (2 levels) in process
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:127 in block in invoke
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/sidekiq.rb:33 in block in call
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:361 in perform_action_with_newrelic_trace
/gems/newrelic_rpm-3.12.1.298/lib/new_relic/agent/instrumentation/sidekiq.rb:29 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:129 in block in invoke
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/server/active_record.rb:6 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:129 in block in invoke
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/server/retry_jobs.rb:74 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:129 in block in invoke
/gems/sidekiq-failures-0.4.5/lib/sidekiq/failures/middleware.rb:9 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:129 in block in invoke
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/server/logging.rb:11 in block in call
/gems/sidekiq-3.5.0/lib/sidekiq/logging.rb:30 in with_context
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/server/logging.rb:7 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:129 in block in invoke
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:132 in call
/gems/sidekiq-3.5.0/lib/sidekiq/middleware/chain.rb:132 in invoke
/gems/sidekiq-3.5.0/lib/sidekiq/processor.rb:51 in block in process
/gems/sidekiq-3.5.0/lib/sidekiq/processor.rb:98 in stats
/gems/sidekiq-3.5.0/lib/sidekiq/processor.rb:50 in process
/gems/celluloid-0.17.1.2/lib/celluloid/calls.rb:28 in public_send
/gems/celluloid-0.17.1.2/lib/celluloid/calls.rb:28 in dispatch
/gems/celluloid-0.17.1.2/lib/celluloid/call/async.rb:7 in dispatch
/gems/celluloid-0.17.1.2/lib/celluloid/cell.rb:50 in block in dispatch
/gems/celluloid-0.17.1.2/lib/celluloid/cell.rb:76 in block in task
/gems/celluloid-0.17.1.2/lib/celluloid/actor.rb:339 in block in task
/gems/celluloid-0.17.1.2/lib/celluloid/task.rb:44 in block in initialize
/gems/celluloid-0.17.1.2/lib/celluloid/task/fibered.rb:14 in block in create

It happens randomly with every few workers.

The record has the following name in the database:

=> {"en"=>"Gründerblog"}

Calling this in the console, causes no errors. Only when doing it async.

calling dirty methods on store fields

let's say i have the title defined with multilang-hstore

I'm unable to get the correct desired effect with the following :
before_update :do_stuff, if: :title_changed?

always returns true. and obviously, whatever's done, the console shows the following :

UPDATE "items" SET "updated_at" = $1, "title" = $2, "content" = $3 WHERE "items"."id" = $4  [["updated_at", 2016-03-06 14:49:25 UTC], ["title", "\"fr\"=>\"title\""], ["id", 1]]

an update. Even if nothing changed

Any thoughts ?

NoMethodError: undefined method `title_will_change!'

Hello!
I've some troubles with using that gem at production environment.
During deploy process I get an error while seeding translated model:

Settings.create!(title: { ru: 'some name' }, subtitle: { ru: 'some other name' }) unless Settings.any?

When I try to reproduce this error in production rails console, it still present with same trace:

from /shared/bundle/ruby/2.1.0/gems/activerecord-.1.6/lib/active_record/attribute_methods.rb:211:in method_missing'
from /shared/bundle/ruby/2.1.0/gems/multilang-hstore-1.0.1/lib/multilang-hstore/translation_keeper.rb:127:in flush!'
from /shared/bundle/ruby/2.1.0/gems/multilang-hstore-1.0.1/lib/multilang-hstore/translation_keeper.rb:39:in update'
from /shared/bundle/ruby/2.1.0/gems/multilang-hstore-1.0.1/lib/multilang-hstore/active_record_extensions.rb:30:in `block (2 levels) in multilang'
from /shared/bundle/ruby/2.1.0/gems/activerecord-4.1.6/lib/active_record/attribute_assignment.rb:45:in public_send'

But I can't reproduce it when launch my application at development machine with production environment flag (all OK).

Can't assign nil to a multilang field

I've noticed some my rspec tests failed because new instance had empty string "" instead of nil:

class CustomField < ActiveRecord::Base
  multilang :name
  ...
end
c = CustomField.new
 => #<CustomField...

c.name
 => ""

c.name = {}
 => {} 

c.name
 => "" 

c.name = {I18n.locale => nil}
 => {:ru=>nil}

c.name
 => "" 

What is the reason of such behavior? PostgreSQL seems to work with NULL values in hstore: http://www.postgresql.org/docs/9.0/static/hstore.html

NameError: undefined local variable or method `actual_locale' for {"en"=>"Featured Image"}:Hash

Having one issue that appears from time to time in my workers.

This is the backtrace. Apparently it's an issue with ActiveModel and its dirty functionality. Does anyone of you have an idea what this could be?

I couldn't really pinpoint it to something in particular, but I think the error has to be around here:
https://www.omniref.com/ruby/gems/activemodel/4.2.0/files/lib/active_model/dirty.rb#line=227

/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:115 in value
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:16 in value
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/active_record_extensions.rb:26 in block (2 levels) in multilang
/gems/activemodel-4.2.4/lib/active_model/dirty.rb:227 in attribute_will_change!
/gems/activemodel-4.2.4/lib/active_model/attribute_methods.rb:385 in title_will_change!
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:127 in flush!
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/translation_keeper.rb:48 in []=
/gems/multilang-hstore-1.0.2/lib/multilang-hstore/active_record_extensions.rb:59 in block (3 levels) in multilang
app/features/importers/hotel_images.rb:66 in convert_data_to_model
app/features/importers/hotel_images.rb:43 in block in set_images
app/features/importers/hotel_images.rb:42 in map
app/features/importers/hotel_images.rb:42 in set_images
app/features/importers/hotel_images.rb:24 in perform
/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:75 in execute_job
/gems/sidekiq-3.4.2/lib/sidekiq/processor.rb:52 in block (2 levels) in process
/gems/sidekiq-3.4.2/lib/sidekiq/middleware/chain.rb:127 in block in invoke

validate all locales rather than specific locale

multilang :content, :required => [:en]

The above validation will validate all locales rather than just :en.

I think line70 is the reason why it happens

In active_record_extensions.rb#L70
# attribute presence validator
if options[:required] == true or locale_required?(options[:required], locale)
module_eval do
validates_presence_of "#{attribute}_#{locale}"
end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.