#初めに
Railsでmodelにスコープを書くことがあるのですがスコープの数が多くなりすぎることがあります。
それで動的にスコープが定義出来たらと思って自分で試してみました。
#具体例
具体的な例として記事に言語の設定があるとします。
モデルはこんな感じ
そんでこのlangはinteger型でenumを使います
なのでmodels/article.rbには
class DataCollect < ApplicationRecord
enum lang: {ja: 0, en: 1, ar: 2, de: 3,el: 4, eo: 5, es: 6, fr: 7}
end
こんな感じに設定します
これでarticleを作成するときにlangを設定してあげれはその記事の言語がわかるようになります。
#scopeを作成
scopeを作成するときに例えば
Article.ja.all
で日本語の記事がとれるようにするためにはmodels/article.rbに
scope :ja, -> {where(lang: :ja)}
とすれば実装できます。
しかし今回の例のように七個も言語があると
models/article.rbは
scope :ja, -> {where(lang: :ja)}
scope :en, -> {where(lang: :en)}
scope :ar, -> {where(lang: :ar)}
scope :de, -> {where(lang: :de)}
scope :el, -> {where(lang: :el)}
scope :eo, -> {where(lang: :eo)}
scope :es, -> {where(lang: :es)}
と書かなくてはいけなくて結構邪魔になります。
もっと増えたらもっと邪魔になるわけでこれをもっと短く書きたい!
#class_evalを使ってみた
とりあえずclass_evalを使ってArticleのモデルにscopeを定義してみます。
使い方はこんな感じになりました。
Article.class_eval { scope ja, -> {where(lang: ja)}
これでscopeの設定ができるので後は配列を作ってループしたら出来上がり。
Lang = [ja, en, ar, de, el, eo, es, fr]
Lang.each do |l|
Article.classs_eval { scope l, -> {where(lang: l)}
end
これでOK
#もう少しいじってみる
もう少しいじってみることにして言語のファイルがconfig/localesにあるのですがそのファイルを見てscopeを定義してみたいと思います。
どういうことかというと
例えばconfig/localesに
en.yml
ja.yml
en.yml
というファイルがあったらそれを見てen,ja,enというスコープを作るということです。
config/localesのファイル名を取得するために
Dir.chdir("/mnt/c/users/owner/desktop/app_name/config/locales")
lang = Dir.glob("*").map {|l| l.match(/../)[0] }
こうすればconfig/localesのファイル名が取得できます。
これでconfig/localesにある言語化ファイルがある言語のスコープを作成できました
完成全体像はこちらです。
class Article < ApplicationRecord
enum lang: {ja: 0, en: 1, ar: 2, de: 3,el: 4, eo: 5, es: 6, fr: 7}
end
Dir.chdir("/mnt/c/users/owner/desktop/latest_news/config/locales")
lang = Dir.glob("*").map {|l| l.match(/../)[0] }
lang.each do |l|
Article.class_eval { scope l, -> {where(lang: l)}}
end
逆にわかりにくいですね(笑)
おわり
メリークリスマス