active-fedora 3.0.1 → 3.0.3
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/History.txt +9 -0
 - data/config/predicate_mappings.yml +1 -0
 - data/lib/active_fedora/associations.rb +73 -0
 - data/lib/active_fedora/associations/association_collection.rb +1 -1
 - data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +117 -0
 - data/lib/active_fedora/base.rb +4 -0
 - data/lib/active_fedora/reflection.rb +1 -1
 - data/lib/active_fedora/semantic_node.rb +1 -1
 - data/lib/active_fedora/version.rb +1 -1
 - data/spec/integration/associations_spec.rb +118 -62
 - metadata +4 -3
 
    
        data/History.txt
    CHANGED
    
    
| 
         @@ -7,6 +7,8 @@ module ActiveFedora 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                autoload :HasManyAssociation, 'active_fedora/associations/has_many_association'
         
     | 
| 
       9 
9 
     | 
    
         
             
                autoload :BelongsToAssociation, 'active_fedora/associations/belongs_to_association'
         
     | 
| 
      
 10 
     | 
    
         
            +
                autoload :HasAndBelongsToManyAssociation, 'active_fedora/associations/has_and_belongs_to_many_association'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                autoload :AssociationCollection, 'active_fedora/associations/association_collection'
         
     | 
| 
       12 
14 
     | 
    
         
             
                autoload :AssociationProxy, 'active_fedora/associations/association_proxy'
         
     | 
| 
         @@ -50,6 +52,73 @@ module ActiveFedora 
     | 
|
| 
       50 
52 
     | 
    
         
             
                  end
         
     | 
| 
       51 
53 
     | 
    
         | 
| 
       52 
54 
     | 
    
         | 
| 
      
 55 
     | 
    
         
            +
                  # Specifies a many-to-many relationship with another class. The relatioship is written to both classes simultaneously.
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # Adds the following methods for retrieval and query:
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # [collection(force_reload = false)]
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   Returns an array of all the associated objects.
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   An empty array is returned if none are found.
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # [collection<<(object, ...)]
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #   Adds one or more objects to the collection by creating associations in the join table
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #   Note that this operation instantly fires update sql without waiting for the save or update call on the
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   parent object.
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # [collection.delete(object, ...)]
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #   Removes one or more objects from the collection by removing their associations from the join table.
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   This does not destroy the objects.
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # [collection=objects]
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #   Replaces the collection's content by deleting and adding objects as appropriate.
         
     | 
| 
      
 72 
     | 
    
         
            +
                  # [collection_singular_ids]
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   Returns an array of the associated objects' ids.
         
     | 
| 
      
 74 
     | 
    
         
            +
                  # [collection_singular_ids=ids]
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #   Replace the collection by the objects identified by the primary keys in +ids+.
         
     | 
| 
      
 76 
     | 
    
         
            +
                  # [collection.clear]
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #   Removes every object from the collection. This does not destroy the objects.
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # [collection.empty?]
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   Returns +true+ if there are no associated objects.
         
     | 
| 
      
 80 
     | 
    
         
            +
                  # [collection.size]
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   Returns the number of associated objects.
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # (+collection+ is replaced with the symbol passed as the first argument, so
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #
         
     | 
| 
      
 86 
     | 
    
         
            +
                  # === Example
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
         
     | 
| 
      
 89 
     | 
    
         
            +
                  # * <tt>Developer#projects</tt>
         
     | 
| 
      
 90 
     | 
    
         
            +
                  # * <tt>Developer#projects<<</tt>
         
     | 
| 
      
 91 
     | 
    
         
            +
                  # * <tt>Developer#projects.delete</tt>
         
     | 
| 
      
 92 
     | 
    
         
            +
                  # * <tt>Developer#projects=</tt>
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # * <tt>Developer#project_ids</tt>
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # * <tt>Developer#project_ids=</tt>
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # * <tt>Developer#projects.clear</tt>
         
     | 
| 
      
 96 
     | 
    
         
            +
                  # * <tt>Developer#projects.empty?</tt>
         
     | 
| 
      
 97 
     | 
    
         
            +
                  # * <tt>Developer#projects.size</tt>
         
     | 
| 
      
 98 
     | 
    
         
            +
                  # * <tt>Developer#projects.find(id)</tt>
         
     | 
| 
      
 99 
     | 
    
         
            +
                  # * <tt>Developer#projects.exists?(...)</tt>
         
     | 
| 
      
 100 
     | 
    
         
            +
                  # The declaration may include an options hash to specialize the behavior of the association.
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # === Options
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # [:class_name]
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #   Specify the class name of the association. Use it only if that name can't be inferred
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #   from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
         
     | 
| 
      
 107 
     | 
    
         
            +
                  #   Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
         
     | 
| 
      
 108 
     | 
    
         
            +
                  # [:property]
         
     | 
| 
      
 109 
     | 
    
         
            +
                  #   <b>REQUIRED</b> Specify the predicate to use when storing the relationship.
         
     | 
| 
      
 110 
     | 
    
         
            +
                  #
         
     | 
| 
      
 111 
     | 
    
         
            +
                  # Option examples:
         
     | 
| 
      
 112 
     | 
    
         
            +
                  #   has_and_belongs_to_many :projects, :property=>:works_on
         
     | 
| 
      
 113 
     | 
    
         
            +
                  #   has_and_belongs_to_many :nations, :class_name => "Country", :property=>:is_citizen_of
         
     | 
| 
      
 114 
     | 
    
         
            +
                  def has_and_belongs_to_many(association_id, options = {}, &extension)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    #configure_after_destroy_method_for_has_and_belongs_to_many(reflection)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    #add_association_callbacks(reflection.name, options)
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       53 
122 
     | 
    
         
             
                  private 
         
     | 
| 
       54 
123 
     | 
    
         | 
| 
       55 
124 
     | 
    
         
             
                    def create_has_many_reflection(association_id, options)
         
     | 
| 
         @@ -60,6 +129,10 @@ module ActiveFedora 
     | 
|
| 
       60 
129 
     | 
    
         
             
                      create_reflection(:belongs_to, association_id, options, self)
         
     | 
| 
       61 
130 
     | 
    
         
             
                    end
         
     | 
| 
       62 
131 
     | 
    
         | 
| 
      
 132 
     | 
    
         
            +
                    def create_has_and_belongs_to_many_reflection(association_id, options)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      create_reflection(:has_and_belongs_to_many, association_id, options, self)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
       63 
136 
     | 
    
         
             
                    def association_accessor_methods(reflection, association_proxy_class)
         
     | 
| 
       64 
137 
     | 
    
         
             
                      redefine_method(reflection.name) do |*params|
         
     | 
| 
       65 
138 
     | 
    
         
             
                        force_reload = params.first unless params.empty?
         
     | 
| 
         @@ -69,7 +69,7 @@ module ActiveFedora 
     | 
|
| 
       69 
69 
     | 
    
         
             
                  # Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
         
     | 
| 
       70 
70 
     | 
    
         
             
                  def <<(*records)
         
     | 
| 
       71 
71 
     | 
    
         
             
                    result = true
         
     | 
| 
       72 
     | 
    
         
            -
                    load_target  
     | 
| 
      
 72 
     | 
    
         
            +
                    load_target unless loaded?
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
       74 
74 
     | 
    
         
             
                    flatten_deeper(records).each do |record|
         
     | 
| 
       75 
75 
     | 
    
         
             
                      raise_on_type_mismatch(record)
         
     | 
| 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveFedora
         
     | 
| 
      
 2 
     | 
    
         
            +
              # = Active Fedora Has And Belongs To Many Association
         
     | 
| 
      
 3 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 4 
     | 
    
         
            +
                class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(owner, reflection)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    super
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def find_target
         
     | 
| 
      
 10 
     | 
    
         
            +
                      @owner.load_outbound_relationship(@reflection.name.to_s, @reflection.options[:property])
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  # def create(attributes = {})
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   create_record(attributes) { |record| insert_record(record) }
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  # def create!(attributes = {})
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   create_record(attributes) { |record| insert_record(record, true) }
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def columns
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @reflection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns")
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  # def reset_column_information
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #   @reflection.reset_column_information
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  # def has_primary_key?
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #   @has_primary_key ||= @owner.connection.supports_primary_key? && @owner.connection.primary_key(@reflection.options[:join_table])
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 35 
     | 
    
         
            +
                    # def construct_find_options!(options)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    #   options[:joins]      = Arel::SqlLiteral.new @join_sql
         
     | 
| 
      
 37 
     | 
    
         
            +
                    #   options[:readonly]   = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
         
     | 
| 
      
 38 
     | 
    
         
            +
                    #   options[:select]   ||= (@reflection.options[:select] || Arel::SqlLiteral.new('*'))
         
     | 
| 
      
 39 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    def count_records
         
     | 
| 
      
 42 
     | 
    
         
            +
                      load_target.size
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    def insert_record(record, force = true, validate = true)
         
     | 
| 
      
 46 
     | 
    
         
            +
                      if record.new_record?
         
     | 
| 
      
 47 
     | 
    
         
            +
                        if force
         
     | 
| 
      
 48 
     | 
    
         
            +
                          record.save!
         
     | 
| 
      
 49 
     | 
    
         
            +
                        else
         
     | 
| 
      
 50 
     | 
    
         
            +
                          return false unless record.save(:validate => validate)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        end
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                      ### TODO save relationship
         
     | 
| 
      
 55 
     | 
    
         
            +
                      @owner.add_relationship(@reflection.options[:property], record)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      record.add_relationship(@reflection.options[:property], @owner)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      record.save
         
     | 
| 
      
 58 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    def delete_records(records)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      records.each do |r| 
         
     | 
| 
      
 63 
     | 
    
         
            +
                        r.remove_relationship(@reflection.options[:property], @owner)
         
     | 
| 
      
 64 
     | 
    
         
            +
                      end
         
     | 
| 
      
 65 
     | 
    
         
            +
                    end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    # def construct_sql
         
     | 
| 
      
 68 
     | 
    
         
            +
                    #   if @reflection.options[:finder_sql]
         
     | 
| 
      
 69 
     | 
    
         
            +
                    #     @finder_sql = interpolate_and_sanitize_sql(@reflection.options[:finder_sql])
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #   else
         
     | 
| 
      
 71 
     | 
    
         
            +
                    #     @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
         
     | 
| 
      
 72 
     | 
    
         
            +
                    #     @finder_sql << " AND (#{conditions})" if conditions
         
     | 
| 
      
 73 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    #   @join_sql = "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    #   construct_counter_sql
         
     | 
| 
      
 78 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    def construct_scope
         
     | 
| 
      
 81 
     | 
    
         
            +
                      { :find => {  :conditions => @finder_sql,
         
     | 
| 
      
 82 
     | 
    
         
            +
                                    :joins => @join_sql,
         
     | 
| 
      
 83 
     | 
    
         
            +
                                    :readonly => false,
         
     | 
| 
      
 84 
     | 
    
         
            +
                                    :order => @reflection.options[:order],
         
     | 
| 
      
 85 
     | 
    
         
            +
                                    :include => @reflection.options[:include],
         
     | 
| 
      
 86 
     | 
    
         
            +
                                    :limit => @reflection.options[:limit] } }
         
     | 
| 
      
 87 
     | 
    
         
            +
                    end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                    # Join tables with additional columns on top of the two foreign keys must be considered
         
     | 
| 
      
 90 
     | 
    
         
            +
                    # ambiguous unless a select clause has been explicitly defined. Otherwise you can get
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # broken records back, if, for example, the join column also has an id column. This will
         
     | 
| 
      
 92 
     | 
    
         
            +
                    # then overwrite the id column of the records coming back.
         
     | 
| 
      
 93 
     | 
    
         
            +
                    def finding_with_ambiguous_select?(select_clause)
         
     | 
| 
      
 94 
     | 
    
         
            +
                      !select_clause && columns.size != 2
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  private
         
     | 
| 
      
 98 
     | 
    
         
            +
                    # def create_record(attributes, &block)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    #   # Can't use Base.create because the foreign key may be a protected attribute.
         
     | 
| 
      
 100 
     | 
    
         
            +
                    #   ensure_owner_is_not_new
         
     | 
| 
      
 101 
     | 
    
         
            +
                    #   if attributes.is_a?(Array)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    #     attributes.collect { |attr| create(attr) }
         
     | 
| 
      
 103 
     | 
    
         
            +
                    #   else
         
     | 
| 
      
 104 
     | 
    
         
            +
                    #     build_record(attributes, &block)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 106 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                    def record_timestamp_columns(record)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      if record.record_timestamps
         
     | 
| 
      
 110 
     | 
    
         
            +
                        record.send(:all_timestamp_attributes).map { |x| x.to_s }
         
     | 
| 
      
 111 
     | 
    
         
            +
                      else
         
     | 
| 
      
 112 
     | 
    
         
            +
                        []
         
     | 
| 
      
 113 
     | 
    
         
            +
                      end
         
     | 
| 
      
 114 
     | 
    
         
            +
                    end
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/active_fedora/base.rb
    CHANGED
    
    | 
         @@ -139,6 +139,10 @@ module ActiveFedora 
     | 
|
| 
       139 
139 
     | 
    
         
             
                  @metadata_is_dirty == false
         
     | 
| 
       140 
140 
     | 
    
         
             
                  return result
         
     | 
| 
       141 
141 
     | 
    
         
             
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                def save!
         
     | 
| 
      
 144 
     | 
    
         
            +
                  save
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
       142 
146 
     | 
    
         | 
| 
       143 
147 
     | 
    
         
             
                # Refreshes the object's info from Fedora
         
     | 
| 
       144 
148 
     | 
    
         
             
                # Note: Currently just registers any new datastreams that have appeared in fedora
         
     | 
| 
         @@ -5,7 +5,7 @@ module ActiveFedora 
     | 
|
| 
       5 
5 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       6 
6 
     | 
    
         
             
                  def create_reflection(macro, name, options, active_fedora)
         
     | 
| 
       7 
7 
     | 
    
         
             
                    case macro
         
     | 
| 
       8 
     | 
    
         
            -
                      when :has_many, :belongs_to
         
     | 
| 
      
 8 
     | 
    
         
            +
                      when :has_many, :belongs_to, :has_and_belongs_to_many
         
     | 
| 
       9 
9 
     | 
    
         
             
                        klass = AssociationReflection
         
     | 
| 
       10 
10 
     | 
    
         
             
                        reflection = klass.new(macro, name, options, active_fedora)
         
     | 
| 
       11 
11 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -6,80 +6,136 @@ end 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            class Book < ActiveFedora::Base 
         
     | 
| 
       8 
8 
     | 
    
         
             
              belongs_to :library, :property=>:has_constituent
         
     | 
| 
      
 9 
     | 
    
         
            +
              has_and_belongs_to_many :topics, :property=>:is_topic_of
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            class Topic < ActiveFedora::Base 
         
     | 
| 
      
 13 
     | 
    
         
            +
              has_and_belongs_to_many :books, :property=>:is_topic_of
         
     | 
| 
       9 
14 
     | 
    
         
             
            end
         
     | 
| 
       10 
15 
     | 
    
         | 
| 
       11 
16 
     | 
    
         
             
            describe ActiveFedora::Base do
         
     | 
| 
       12 
17 
     | 
    
         
             
              describe "an unsaved instance" do
         
     | 
| 
       13 
     | 
    
         
            -
                 
     | 
| 
       14 
     | 
    
         
            -
                   
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                   
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                end
         
     | 
| 
       40 
     | 
    
         
            -
                it "should let you set an array of object ids" do
         
     | 
| 
       41 
     | 
    
         
            -
                  @library.book_ids = [@book.pid, @book2.pid]
         
     | 
| 
       42 
     | 
    
         
            -
                  @library.books.map(&:pid).should == [@book.pid, @book2.pid]
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                it "setter should wipe out previously saved relations" do
         
     | 
| 
       46 
     | 
    
         
            -
                  @library.book_ids = [@book.pid, @book2.pid]
         
     | 
| 
       47 
     | 
    
         
            -
                  @library.book_ids = [@book2.pid]
         
     | 
| 
       48 
     | 
    
         
            -
                  @library.books.map(&:pid).should == [@book2.pid]
         
     | 
| 
      
 18 
     | 
    
         
            +
                describe "of belongs_to" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @library = Library.new()
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @book = Book.new
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @book.save
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @book2 = Book.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @book2.save
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  it "should let you shift onto the association" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @library.new_record?.should be_true
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @library.books.size == 0
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @library.books.to_ary.should == []
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @library.book_ids.should ==[]
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @library.books << @book
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book.pid]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @library.book_ids.should ==[@book.pid]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  it "should let you set an array of objects" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @library.books = [@book, @book2]
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book.pid, @book2.pid]
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @library.save
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    @library.books = [@book]
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book.pid]
         
     | 
| 
       49 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                  it "should let you set an array of object ids" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @library.book_ids = [@book.pid, @book2.pid]
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book.pid, @book2.pid]
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  it "setter should wipe out previously saved relations" do
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @library.book_ids = [@book.pid, @book2.pid]
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @library.book_ids = [@book2.pid]
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book2.pid]
         
     | 
| 
      
 55 
     | 
    
         
            +
                    
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  after do
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @book.delete
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @book2.delete
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
       50 
63 
     | 
    
         
             
                end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
                describe "of has_many_and_belongs_to" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @topic1 = Topic.new
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @topic1.save
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @topic2 = Topic.new
         
     | 
| 
      
 69 
     | 
    
         
            +
                    @topic2.save
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  it "habtm should set relationships bidirectionally" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                    @book = Book.new
         
     | 
| 
      
 73 
     | 
    
         
            +
                    @book.topics << @topic1
         
     | 
| 
      
 74 
     | 
    
         
            +
                    @book.topics.map(&:pid).should == [@topic1.pid]
         
     | 
| 
      
 75 
     | 
    
         
            +
                    Topic.find(@topic1.pid).books.map(&:pid).should == [] #Can't have saved it because @book isn't saved yet.
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  after do
         
     | 
| 
      
 78 
     | 
    
         
            +
                    @topic1.delete
         
     | 
| 
      
 79 
     | 
    
         
            +
                    @topic2.delete
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
       55 
81 
     | 
    
         
             
                end
         
     | 
| 
       56 
82 
     | 
    
         
             
              end
         
     | 
| 
       57 
83 
     | 
    
         | 
| 
      
 84 
     | 
    
         
            +
              
         
     | 
| 
       58 
85 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
              describe "a saved instance" do
         
     | 
| 
       60 
     | 
    
         
            -
                before do
         
     | 
| 
       61 
     | 
    
         
            -
                  @library = Library.new()
         
     | 
| 
       62 
     | 
    
         
            -
                  @library.save()
         
     | 
| 
       63 
     | 
    
         
            -
                  @book = Book.new
         
     | 
| 
       64 
     | 
    
         
            -
                  @book.save
         
     | 
| 
       65 
     | 
    
         
            -
                end
         
     | 
| 
       66 
     | 
    
         
            -
                it "should have many books once it has been saved" do
         
     | 
| 
       67 
     | 
    
         
            -
                  @library.save
         
     | 
| 
       68 
     | 
    
         
            -
                  @library.books << @book
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                  @book.library.pid.should == @library.pid
         
     | 
| 
       71 
     | 
    
         
            -
                  @library.books.reload
         
     | 
| 
       72 
     | 
    
         
            -
                  @library.books.map(&:pid).should == [@book.pid]
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                  @library2 = Library.find(@library.pid)
         
     | 
| 
       76 
     | 
    
         
            -
                  @library2.books.map(&:pid).should == [@book.pid]
         
     | 
| 
       77 
86 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
      
 87 
     | 
    
         
            +
              describe "a saved instance" do
         
     | 
| 
      
 88 
     | 
    
         
            +
                describe "of belongs_to" do
         
     | 
| 
      
 89 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @library = Library.new()
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @library.save()
         
     | 
| 
      
 92 
     | 
    
         
            +
                    @book = Book.new
         
     | 
| 
      
 93 
     | 
    
         
            +
                    @book.save
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  it "should have many books once it has been saved" do
         
     | 
| 
      
 96 
     | 
    
         
            +
                    @library.books << @book
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    @book.library.pid.should == @library.pid
         
     | 
| 
      
 99 
     | 
    
         
            +
                    @library.books.reload
         
     | 
| 
      
 100 
     | 
    
         
            +
                    @library.books.map(&:pid).should == [@book.pid]
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    @library2 = Library.find(@library.pid)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    @library2.books.map(&:pid).should == [@book.pid]
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                  after do
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @library.delete
         
     | 
| 
      
 108 
     | 
    
         
            +
                    @book.delete
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
       79 
110 
     | 
    
         
             
                end
         
     | 
| 
       80 
     | 
    
         
            -
                 
     | 
| 
       81 
     | 
    
         
            -
                   
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
      
 111 
     | 
    
         
            +
                describe "of has_many_and_belongs_to" do
         
     | 
| 
      
 112 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 113 
     | 
    
         
            +
                    @topic1 = Topic.new
         
     | 
| 
      
 114 
     | 
    
         
            +
                    @topic1.save
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @topic2 = Topic.new
         
     | 
| 
      
 116 
     | 
    
         
            +
                    @topic2.save
         
     | 
| 
      
 117 
     | 
    
         
            +
                    @book = Book.new
         
     | 
| 
      
 118 
     | 
    
         
            +
                    @book.save
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  it "habtm should set relationships bidirectionally" do
         
     | 
| 
      
 121 
     | 
    
         
            +
                    @book.topics << @topic1
         
     | 
| 
      
 122 
     | 
    
         
            +
                    @book.topics.map(&:pid).should == [@topic1.pid]
         
     | 
| 
      
 123 
     | 
    
         
            +
                    Topic.find(@topic1.pid).books.map(&:pid).should == [@book.pid] #Can't have saved it because @book isn't saved yet.
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
                  it "should save new child objects" do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    @book.topics << Topic.new
         
     | 
| 
      
 127 
     | 
    
         
            +
                    @book.topics.first.pid.should_not be_nil
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  it "should clear out the old associtions" do
         
     | 
| 
      
 130 
     | 
    
         
            +
                    @book.topics = [@topic1]
         
     | 
| 
      
 131 
     | 
    
         
            +
                    @book.topics = [@topic2]
         
     | 
| 
      
 132 
     | 
    
         
            +
                    @book.topic_ids.should == [@topic2.pid]
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                  after do
         
     | 
| 
      
 135 
     | 
    
         
            +
                    @book.delete
         
     | 
| 
      
 136 
     | 
    
         
            +
                    @topic1.delete
         
     | 
| 
      
 137 
     | 
    
         
            +
                    @topic2.delete
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
       83 
139 
     | 
    
         
             
                end
         
     | 
| 
       84 
140 
     | 
    
         
             
              end
         
     | 
| 
       85 
141 
     | 
    
         | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,13 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification 
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: active-fedora
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version 
         
     | 
| 
       4 
     | 
    
         
            -
              hash:  
     | 
| 
      
 4 
     | 
    
         
            +
              hash: 1
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
6 
     | 
    
         
             
              segments: 
         
     | 
| 
       7 
7 
     | 
    
         
             
              - 3
         
     | 
| 
       8 
8 
     | 
    
         
             
              - 0
         
     | 
| 
       9 
     | 
    
         
            -
              -  
     | 
| 
       10 
     | 
    
         
            -
              version: 3.0. 
     | 
| 
      
 9 
     | 
    
         
            +
              - 3
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 3.0.3
         
     | 
| 
       11 
11 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       12 
12 
     | 
    
         
             
            authors: 
         
     | 
| 
       13 
13 
     | 
    
         
             
            - Matt Zumwalt
         
     | 
| 
         @@ -520,6 +520,7 @@ files: 
     | 
|
| 
       520 
520 
     | 
    
         
             
            - lib/active_fedora/associations/association_collection.rb
         
     | 
| 
       521 
521 
     | 
    
         
             
            - lib/active_fedora/associations/association_proxy.rb
         
     | 
| 
       522 
522 
     | 
    
         
             
            - lib/active_fedora/associations/belongs_to_association.rb
         
     | 
| 
      
 523 
     | 
    
         
            +
            - lib/active_fedora/associations/has_and_belongs_to_many_association.rb
         
     | 
| 
       523 
524 
     | 
    
         
             
            - lib/active_fedora/associations/has_many_association.rb
         
     | 
| 
       524 
525 
     | 
    
         
             
            - lib/active_fedora/attribute_methods.rb
         
     | 
| 
       525 
526 
     | 
    
         
             
            - lib/active_fedora/base.rb
         
     |