prim 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|