Plan¶ ↑
Working on sti branch will target to 0.3 version which will not compatible with 0.1 and 0.2
Intro¶ ↑
There are always some static data(not static page) in application.For example product type or student diploma type.
This gem can map these static data to a Dictionary#method like Dictionary#student_diploma_kind and generate a list of instance method on Student like @student.named_city which return city name (with locale if you need).
Usage¶ ↑
Installation¶ ↑
Branch sti is used to target version 0.3 which will totall rewrite. The main change is use STI to replace dict_types.
Version 0.2 support Rails4
Version 0.1 support Rails3.1
gem 'rails_dictionary'
or
gem "rails_dictionary", :git => 'git://github.com/raykin/rails_dictionary'
!!For users who update from old version to 0.0.9.1 or higher,Please run following command on app root after updates.
rails runner "DictType.new.delete_all_caches"
and in production
rails runner "DictType.new.delete_all_caches" -e production
or if you use file cache,just run
rake tmp:clear
See change log for brief info.
Sample¶ ↑
Run following task will give you a simple start.Maybe you should try it in a new application first.
rake dicts:generate rake dicts:sample_slave rake db:migrate rake dicts:sample_data
These task are just generate table dictionaries,dict_types,students and some sample data.The data should be
irb(main):013:0> DictType.select("id,name").all DictType Load (0.4ms) SELECT id,name FROM `dict_types` +----+----------------+ | id | name | +----+----------------+ | 1 | student_city | | 2 | student_school | +----+----------------+ 2 rows in set irb(main):014:0> Dictionary.select("id,name_en,name_zh,name_fr,dict_type_id").all Dictionary Load (1.2ms) SELECT id,name_en,name_zh,name_fr,dict_type_id FROM `dictionaries` +----+----------+---------+----------+--------------+ | id | name_en | name_zh | name_fr | dict_type_id | +----+----------+---------+----------+--------------+ | 3 | shanghai | 上海 | shanghai | 1 | | 4 | beijing | 北京 | Pékin | 1 | +----+----------+---------+----------+--------------+ 2 rows in set irb(main):016:0> Student.select("id,email,city,school").all Student Load (0.4ms) SELECT id,email,city,school FROM `students` +----+-------------------+------+--------+ | id | email | city | school | +----+-------------------+------+--------+ | 1 | beijing@dict.com | 4 | | | 2 | shanghai@dict.com | 3 | | +----+-------------------+------+--------+ 2 rows in set
There is one convention on DictType.name .All value of DictType.name is “model_method” : student is model and city is method of student model.
Table Definition¶ ↑
Make sure you have two tables which named as dict_types and dictionaries.
Table dictionaries has one convention of naming column : name_locale.So the name_fr means this column have a french value,you can see more usage later. The students table is not required and variable by your application.
Class Definition¶ ↑
Here is what should be like.Student model can be other models.
class DictType < ActiveRecord::Base acts_as_dict_type end class Dictionary < ActiveRecord::Base acts_as_dictionary end class Student < ActiveRecord::Base # use acts_as_dict_slave when your rails_dictionary version < 0.2 acts_as_dict_consumer end
Features (relies on the above data) :¶ ↑
DictType.all_cached #=> return cache of DictType.all DictType.all_types = [:student_city,:student_school] # also cached Dictionary.student_city #=> [Dictionary.find(5),Dictionary.find(6)]
student_city is a dynamic method(from method missing) which returns a list of dictionary object which dict_type is “student_city”. Actually Dictionary will have as many dynamic methods as DictType.count and each dynamic method name is DictType.name. And student_city return an array,not ActiveRelation.So
Dictionary.student_school = [] Dictionary.student_city :locale => :en #=> [["beijing", 2],["shanghai",1]]
If you need a ActiveRelation, try scoped_student_city like
Dictionary.scoped_student_city.where(...)
You can use it in form select method like
collection_select :student,:city,Dictionary.student_city,:id,:name_en select :student,:city,Dictionary.student_city(params)
If params contains :locale => :fr,it returns a list of french name of student city (from name_fr in Dictioanry)
Student.find(1).named_city = "beijing" # when default locale is :en
Here is an other solution for international translation.
Student.find(1).named_city(:zh) = "北京" Student.find(1).named_city(:fr) = "Pékin" Student.find(1).named_city(:en) = "beijing"
Make sure your locale is en,not en-US.
Student has two belongs_to assocition which named as city_dict and school_dict,the naming convention is method_dict.
Student.find(1).city_dict #=> Dictionary.find(6)
Sort Feature¶ ↑
Static data need orders frequently,so Dictionary.student_city :locale => :en has a default sort rules. By default,if the options contains locale,the results are sorted by the name value. If locale is :zh,sort rule is order by GBK encoding. Other locales are just order by alphabetical without case sensitive. You can override Dictionary.sort_dicts to customize your sort rule.But it is not recommended now as the code of sort design maybe change in a few month.
Practical Suggestion¶ ↑
If you start a new application and there are more than 10 kinds of static data,you may have a try with the gem. However,if you see many static data in an old system and want to refactor it,the decision would be judged by the real situations.
Beware¶ ↑
The most used debug method would be DictType.all_types and Dictionary.student_city(or other dynamic generate method) When you get some confused with the output of these method,try running
rails tmp:clear
cause these methods all return static data(may be a mass of data),I just caches these output for better performance.If you change db data in db console(not through Rails) like running
delete from dict_types;
The rails cache would not refresh. In short,when you confused with the debug data,try running “rails tmp:clear” first.
TODO & Problems¶ ↑
Remove engine. Becase for the view layer we can use gem rails_admin. so this gem did not need rails engine. Is there any exist low level method to monitor the change of descendents? Add test code for cache DictType.tab_and_column,then uncomment the cache code.
There are no conventions and implemention to map Class like Ckeditor::Asset to a legal method name.