prim 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +23 -0
- data/README.md +6 -2
- data/lib/prim.rb +3 -3
- data/lib/prim/collection.rb +11 -17
- data/lib/prim/instance_methods.rb +40 -10
- data/lib/prim/relationship.rb +6 -4
- data/prim.gemspec +4 -3
- metadata +19 -2
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
LICENSE
|
2
|
+
|
3
|
+
The MIT License
|
4
|
+
|
5
|
+
Copyright (c) 2012 Piers Mainwaring and Orca Health, Inc.
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
15
|
+
all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -32,9 +32,13 @@ end
|
|
32
32
|
|
33
33
|
Great! Now let's say we've added a specific set of Languages. Our Users can now have new Language associations by simply creating a record in the `user_languages` mapping table, relating a User and a Language. But what if we want to know which of a User's Languages is their most important? Well, we could add a `sort_order` or `primary` column to the `user_languages` table, but then we'll need to write code to manage it all.
|
34
34
|
|
35
|
-
Enter __Prim__.
|
35
|
+
Enter __Prim__. Add
|
36
36
|
|
37
|
-
|
37
|
+
```ruby
|
38
|
+
gem 'prim'
|
39
|
+
```
|
40
|
+
|
41
|
+
to your Gemfile. With __Prim__ we can just add a line of code to the User model...
|
38
42
|
|
39
43
|
```ruby
|
40
44
|
class User < ActiveRecord::Base
|
data/lib/prim.rb
CHANGED
@@ -27,11 +27,11 @@ module Prim
|
|
27
27
|
Prim.configured_primaries << self.prim_relationships[ singular_name ]
|
28
28
|
|
29
29
|
define_method "primary_#{ singular_name }" do
|
30
|
-
|
30
|
+
prim_collection_for(singular_name).primary
|
31
31
|
end
|
32
32
|
|
33
|
-
define_method "primary_#{ singular_name }=" do |
|
34
|
-
|
33
|
+
define_method "primary_#{ singular_name }=" do |instance|
|
34
|
+
prim_collection_for(singular_name).primary = instance
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/prim/collection.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Prim
|
2
2
|
# Collection largely wraps an association collection (like a Relation) but adds
|
3
3
|
# the concept of a primary member. Collections can only exist in the context of
|
4
|
-
# a Relationship (see Prim::Relationship for more info) and an `
|
4
|
+
# a Relationship (see Prim::Relationship for more info) and an "owning" `instance`,
|
5
5
|
# and contain mapping records.
|
6
6
|
class Collection
|
7
7
|
|
@@ -14,14 +14,20 @@ module Prim
|
|
14
14
|
@instance = instance
|
15
15
|
@relationship = relationship
|
16
16
|
|
17
|
-
# Attach
|
18
|
-
relationship.reflected_class.
|
17
|
+
# Attach the relationship to the mapping class.
|
18
|
+
relationship.reflected_class.prim_relationship = relationship
|
19
19
|
end
|
20
20
|
|
21
|
+
# Loads the primary member of this collection.
|
21
22
|
def primary
|
22
|
-
sources.where( relationship.
|
23
|
+
sources.where( relationship.collection_label => { primary: true } ).first.try do |record|
|
24
|
+
record.primary = true
|
25
|
+
record
|
26
|
+
end
|
23
27
|
end
|
24
28
|
|
29
|
+
# Sets the primary member of this collection. Requires a `source_record` to
|
30
|
+
# be passed (i.e. a Tag if Post `has_many :tags, through: :taggings`).
|
25
31
|
def primary= source_record
|
26
32
|
mapping = mapping_for(source_record)
|
27
33
|
|
@@ -40,18 +46,6 @@ module Prim
|
|
40
46
|
true
|
41
47
|
end
|
42
48
|
|
43
|
-
def siblings_for mapping
|
44
|
-
foreign_key = relationship.mapping_reflection.foreign_key
|
45
|
-
mapping_type = relationship.mapping_reflection.type
|
46
|
-
mapping_class = relationship.reflected_class
|
47
|
-
primary_key = mapping_class.primary_key
|
48
|
-
|
49
|
-
query = relationship.reflected_class.where( foreign_key => mapping[ foreign_key ] )
|
50
|
-
query = query.where( mapping_type => mapping[ mapping_type ] ) unless mapping_type.nil?
|
51
|
-
|
52
|
-
query.where( mapping_class.arel_table[ primary_key ].not_eq( mapping[ primary_key ] ) )
|
53
|
-
end
|
54
|
-
|
55
49
|
private
|
56
50
|
|
57
51
|
# Creates a new source record and a mapping between it and the owner instance.
|
@@ -68,7 +62,7 @@ module Prim
|
|
68
62
|
end
|
69
63
|
|
70
64
|
def mappings force_reload = false
|
71
|
-
instance.send( relationship.
|
65
|
+
instance.send( relationship.collection_label, force_reload )
|
72
66
|
end
|
73
67
|
|
74
68
|
def sources force_reload = false
|
@@ -5,15 +5,7 @@ module Prim
|
|
5
5
|
module InstanceMethods
|
6
6
|
|
7
7
|
module Owner
|
8
|
-
def
|
9
|
-
collection_for(singular_name).primary
|
10
|
-
end
|
11
|
-
|
12
|
-
def assign_primary singular_name, instance
|
13
|
-
collection_for(singular_name).primary = instance
|
14
|
-
end
|
15
|
-
|
16
|
-
def collection_for singular_name
|
8
|
+
def prim_collection_for singular_name
|
17
9
|
@_prim_collections ||= {}
|
18
10
|
@_prim_collections[ singular_name ] ||= Prim::Collection.new(self.class.prim_relationships[ singular_name ], self)
|
19
11
|
end
|
@@ -24,6 +16,10 @@ module Prim
|
|
24
16
|
|
25
17
|
included do
|
26
18
|
validate :only_one_primary
|
19
|
+
|
20
|
+
def self.primary
|
21
|
+
where( primary: true ).first
|
22
|
+
end
|
27
23
|
end
|
28
24
|
|
29
25
|
def only_one_primary
|
@@ -32,8 +28,42 @@ module Prim
|
|
32
28
|
end
|
33
29
|
end
|
34
30
|
|
31
|
+
# Builds a query selecting all siblings for a given mapping record. A record's
|
32
|
+
# siblings are any records in the table of the `reflected_class` that match
|
33
|
+
# the given record's foreign key and, if the association is polymorphic,
|
34
|
+
# its foreign type. The set of siblings *excludes* `self` (this record).
|
35
35
|
def siblings
|
36
|
-
|
36
|
+
foreign_key = prim_relationship.mapping_reflection.foreign_key
|
37
|
+
mapping_type = prim_relationship.mapping_reflection.type
|
38
|
+
primary_key = prim_relationship.reflected_class.primary_key
|
39
|
+
|
40
|
+
# Select all by foreign key first, to handle all cases.
|
41
|
+
query = self.class.where( foreign_key => self[ foreign_key ] )
|
42
|
+
|
43
|
+
# Only select by a foreign "type" column if one is used on the `reflected_class`,
|
44
|
+
# making it a polymorphic association.
|
45
|
+
unless mapping_type.nil?
|
46
|
+
query = query.where( mapping_type => self[ mapping_type ] )
|
47
|
+
end
|
48
|
+
|
49
|
+
# Exclude this record from the query.
|
50
|
+
query.where( self.class.arel_table[ primary_key ].not_eq( self[ primary_key ] ) )
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Source
|
55
|
+
extend ActiveSupport::Concern
|
56
|
+
|
57
|
+
included do
|
58
|
+
attr_writer :primary
|
59
|
+
|
60
|
+
def primary
|
61
|
+
@primary || false
|
62
|
+
end
|
63
|
+
|
64
|
+
def primary?
|
65
|
+
primary
|
66
|
+
end
|
37
67
|
end
|
38
68
|
end
|
39
69
|
|
data/lib/prim/relationship.rb
CHANGED
@@ -34,17 +34,19 @@ module Prim
|
|
34
34
|
# TODO: ensure the association isn't nested?
|
35
35
|
|
36
36
|
reflected_class.send :include, InstanceMethods::Reflected
|
37
|
-
reflected_class.class_attribute :
|
37
|
+
reflected_class.class_attribute :prim_relationship
|
38
|
+
|
39
|
+
source_class.send :include, InstanceMethods::Source if mapping_table?
|
38
40
|
end
|
39
41
|
|
40
42
|
# The association method to call on the owning class to retrieve a record's collection.
|
41
|
-
def
|
43
|
+
def collection_label
|
42
44
|
options[:through] || mapping_reflection.plural_name
|
43
45
|
end
|
44
46
|
|
45
47
|
# The class of the reflection source: i.e. Post if the owning class `has_many :posts`.
|
46
48
|
def source_class
|
47
|
-
|
49
|
+
reflection.klass
|
48
50
|
end
|
49
51
|
|
50
52
|
# The class of the `mapping_reflection`.
|
@@ -55,7 +57,7 @@ module Prim
|
|
55
57
|
# The association reflection representing the link between the owning class and the
|
56
58
|
# mapping class, whether or not the mapping class represents a join-table.
|
57
59
|
def mapping_reflection
|
58
|
-
through_reflection ||
|
60
|
+
through_reflection || reflection
|
59
61
|
end
|
60
62
|
|
61
63
|
# True if this relationship relies on a mapping table for `primary` records.
|
data/prim.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "prim"
|
3
|
-
s.version = "0.0.
|
4
|
-
s.date = "
|
3
|
+
s.version = "0.0.4"
|
4
|
+
s.date = "2013-01-02"
|
5
5
|
s.summary = "Easily manage Rails associations that need a primary member."
|
6
6
|
s.description = "With Prim it's easy to add a primary member to any one-to-many or many-to-many association. " +
|
7
7
|
"Just add a short configuration to a model, generate and run a migration, and you're all set."
|
@@ -10,7 +10,8 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.files = `git ls-files`.split("\n")
|
11
11
|
s.homepage = "https://github.com/orcahealth/prim"
|
12
12
|
|
13
|
-
s.add_dependency "activerecord",
|
13
|
+
s.add_dependency "activerecord", "~> 3.2.0"
|
14
|
+
s.add_dependency "activesupport", "~> 3.2.0"
|
14
15
|
|
15
16
|
s.require_paths = [ "lib" ]
|
16
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: 3.2.0
|
29
29
|
none: false
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
prerelease: false
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.2.0
|
38
|
+
none: false
|
39
|
+
type: :runtime
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 3.2.0
|
45
|
+
none: false
|
30
46
|
description: With Prim it's easy to add a primary member to any one-to-many or many-to-many
|
31
47
|
association. Just add a short configuration to a model, generate and run a migration,
|
32
48
|
and you're all set.
|
@@ -35,6 +51,7 @@ executables: []
|
|
35
51
|
extensions: []
|
36
52
|
extra_rdoc_files: []
|
37
53
|
files:
|
54
|
+
- LICENSE
|
38
55
|
- README.md
|
39
56
|
- lib/prim.rb
|
40
57
|
- lib/prim/collection.rb
|