Module: PlainRecord::Associations
- Included in:
- Model
- Defined in:
- lib/plain_record/associations.rb
Overview
Extention for model to store or have link to another model. There is two type of association.
Virtual field
In virtual
method this filter create only link to another model. When you try to use this virtual field, model will find association object by rules in map
.
Rules in map
is only Hash with model fields in key and association fields in value. For example, if model contain name
field and association must have post_name
with same value, map
will be { :name => :post_name }
.
If you didn’t set map
filter will try to find it automatically: it will find in model and association class all field pairs, what have name like field
→ model
_field
. For example, if model Post
have field name
and Comment
have post_name
, you may not set map
– filter will find it automatically.
class Review
include PlainRecord::Resource
entry_in 'reviews/*.md'
virtual :author, one(Author)
field :author_login
text :review
end
class Author
include PlainRecord::Resource
list_in 'authors.yml'
virtual :reviews, many(Review)
field :login
field :name
end
Real field
If you will use this filter in field
method, association object data will store in you model file. For example model:
class Movie
include PlainRecord::Resource
field :title
field :genre
field :release_year
end
class Tag
include PlainRecord::Resource
field :name
end
class Review
include PlainRecord::Resource
entry_in 'reviews/*.md'
field :author
field :movie, one(Movie)
field :tags, many(Tag)
text :review
end
will be store as:
author: John Smith
movie:
title: Watchmen
genre: action
release_year: 2009
tags:
- name: Great movies
- name: Comics
---
Movie is great!
Instance Attribute Summary collapse
-
#association_maps ⇒ Object
Hash with map for virtual associations.
Class Method Summary collapse
-
.define_link_many(klass, model, name, map) ⇒ Object
Define that virtual field
name
inklass
contain links tomodel
witch are finded bymap
. -
.define_link_one(klass, model, name, map) ⇒ Object
Define that virtual field
name
inklass
contain link tomodel
witch is finded bymap
. -
.define_real_many(klass, field, model) ⇒ Object
Define, that
field
inklass
contain in file array of data frommodel
objects. -
.define_real_one(klass, field, model) ⇒ Object
Define, that
field
inklass
contain in file data frommodel
. - .init_association_cache(klass) ⇒ Object
-
.map(from, to, prefix) ⇒ Object
Find fields pairs in
from
andto
models, witch is likeprefix
_from
→to
.
Instance Attribute Details
#association_maps ⇒ Object
Hash with map for virtual associations.
103 104 105 |
# File 'lib/plain_record/associations.rb', line 103 def association_maps @association_maps end |
Class Method Details
.define_link_many(klass, model, name, map) ⇒ Object
Define that virtual field name
in klass
contain links to model
witch are finded by map
.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/plain_record/associations.rb', line 252 def define_link_many(klass, model, name, map) klass.association_maps ||= { } klass.association_maps[name] = map init_association_cache(klass) klass.add_accessors <<-EOS, __FILE__, __LINE__ def #{name} unless @association_cache.has_key? :#{name} search = Hash[ self.class.association_maps[:#{name}].map do |from, to| [from, send(to)] end] @association_cache[:#{name}] = AssociationProxy.new( #{model}.all(search), self, :#{name}) end @association_cache[:#{name}] end def #{name}=(values) @association_cache[:#{name}] = AssociationProxy.link( values, self, :#{name}) end EOS end |
.define_link_one(klass, model, name, map) ⇒ Object
Define that virtual field name
in klass
contain link to model
witch is finded by map
.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/plain_record/associations.rb', line 225 def define_link_one(klass, model, name, map) klass.association_maps ||= { } klass.association_maps[name] = map init_association_cache(klass) klass.add_accessors <<-EOS, __FILE__, __LINE__ def #{name} unless @association_cache.has_key? :#{name} search = Hash[ self.class.association_maps[:#{name}].map do |from, to| [to, send(from)] end] @association_cache[:#{name}] = #{model}.first(search) end @association_cache[:#{name}] end def #{name}=(value) self.class.association_maps[:#{name}].each do |from, to| value.send(to.to_s + '=', send(from)) end @association_cache[:#{name}] = value end EOS end |
.define_real_many(klass, field, model) ⇒ Object
Define, that field
in klass
contain in file array of data from model
objects.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/plain_record/associations.rb', line 169 def define_real_many(klass, field, model) name = field.to_s klass.after :load do |result, entry| if entry.data[name].is_a? Enumerable entry.data[name].map! { |i| model.new(entry.file, i) } else entry.data[name] = [] end result end klass.before :save do |entry| if entry.data[name].empty? entry.data.delete(name) else entry.data[name].map! do |obj| model.call_before_callbacks(:save, [obj]) obj.data end end end klass.after :save do |result, entry| entry.data[name].map! { |i| model.new(entry.file, i) } entry.data[name].each do |i| model.call_after_callbacks(:save, nil, [i]) end result end end |
.define_real_one(klass, field, model) ⇒ Object
Define, that field
in klass
contain in file data from model
.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/plain_record/associations.rb', line 144 def define_real_one(klass, field, model) name = field.to_s klass.after :load do |result, entry| if entry.data[name] entry.data[name] = model.new(entry.file, entry.data[name]) end result end klass.before :save do |entry| if entry.data[name] model.call_before_callbacks(:save, [entry.data[name]]) entry.data[name] = entry.data[name] end end klass.after :save do |result, entry| if entry.data[name] entry.data[name] = model.new(entry.file, entry.data[name]) model.call_after_callbacks(:save, nil, [entry.data[name]]) end result end end |
.init_association_cache(klass) ⇒ Object
217 218 219 220 221 |
# File 'lib/plain_record/associations.rb', line 217 def init_association_cache(klass) klass.after :load do |result, entry| entry.instance_exec { @association_cache = { } } end end |
.map(from, to, prefix) ⇒ Object
Find fields pairs in from
and to
models, witch is like prefix
_from
→ to
.
For example, if Comment contain post_name
field and Post contain name
:
Associations.map(Comment, Post, :post) #=> { :post_name => :name }
205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/plain_record/associations.rb', line 205 def map(from, to, prefix) from_fields = (from.fields + from.virtuals).map { |i| i.to_s } mapped = { } (to.fields + to.virtuals).each do |to_field| from_field = prefix + to_field.to_s if from_fields.include? from_field mapped[from_field.to_sym] = to_field end end mapped end |