Skip to content

raykin/rails_dictionary

Repository files navigation

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  | [email protected]  | 4    |        |
   | 2  | [email protected] | 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.

About

Mapping static data to Dictionary Class

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages