citier4 0.0.1

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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +32 -0
  5. data/lib/citier4/acts_as_citier4.rb +95 -0
  6. data/lib/citier4/child_instance_methods.rb +111 -0
  7. data/lib/citier4/core_ext.rb +118 -0
  8. data/lib/citier4/instance_methods.rb +41 -0
  9. data/lib/citier4/relation_methods.rb +139 -0
  10. data/lib/citier4/root_class_methods.rb +36 -0
  11. data/lib/citier4/root_instance_methods.rb +47 -0
  12. data/lib/citier4/version.rb +3 -0
  13. data/lib/citier4.rb +34 -0
  14. data/lib/tasks/citier4_tasks.rake +4 -0
  15. data/test/acts_as_citier4_test.rb +10 -0
  16. data/test/child_instance_methods_test.rb +70 -0
  17. data/test/citier4_test.rb +7 -0
  18. data/test/core_ext_test.rb +7 -0
  19. data/test/deleting_methods_test.rb +101 -0
  20. data/test/dummy/README.rdoc +28 -0
  21. data/test/dummy/Rakefile +6 -0
  22. data/test/dummy/app/assets/javascripts/application.js +13 -0
  23. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  24. data/test/dummy/app/controllers/application_controller.rb +5 -0
  25. data/test/dummy/app/helpers/application_helper.rb +2 -0
  26. data/test/dummy/app/models/animal.rb +16 -0
  27. data/test/dummy/app/models/bidule.rb +2 -0
  28. data/test/dummy/app/models/book.rb +7 -0
  29. data/test/dummy/app/models/dictionary.rb +3 -0
  30. data/test/dummy/app/models/fiction.rb +3 -0
  31. data/test/dummy/app/models/product.rb +8 -0
  32. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  33. data/test/dummy/bin/bundle +3 -0
  34. data/test/dummy/bin/rails +4 -0
  35. data/test/dummy/bin/rake +4 -0
  36. data/test/dummy/config/application.rb +23 -0
  37. data/test/dummy/config/boot.rb +5 -0
  38. data/test/dummy/config/database.yml +25 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +37 -0
  41. data/test/dummy/config/environments/production.rb +78 -0
  42. data/test/dummy/config/environments/test.rb +39 -0
  43. data/test/dummy/config/initializers/assets.rb +8 -0
  44. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  46. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/test/dummy/config/initializers/inflections.rb +16 -0
  48. data/test/dummy/config/initializers/mime_types.rb +4 -0
  49. data/test/dummy/config/initializers/session_store.rb +3 -0
  50. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  51. data/test/dummy/config/locales/en.yml +23 -0
  52. data/test/dummy/config/routes.rb +56 -0
  53. data/test/dummy/config/secrets.yml +22 -0
  54. data/test/dummy/config.ru +4 -0
  55. data/test/dummy/db/development.sqlite3 +0 -0
  56. data/test/dummy/db/migrate/20141228200436_create_products.rb +10 -0
  57. data/test/dummy/db/migrate/20141228200756_create_books.rb +17 -0
  58. data/test/dummy/db/migrate/20150101181703_create_dictionaries.rb +16 -0
  59. data/test/dummy/db/migrate/20150101181916_create_fictions.rb +14 -0
  60. data/test/dummy/db/migrate/20150102200342_create_bidules.rb +9 -0
  61. data/test/dummy/db/migrate/20150102200786_create_animals.rb +10 -0
  62. data/test/dummy/db/schema.rb +81 -0
  63. data/test/dummy/db/test.sqlite3 +0 -0
  64. data/test/dummy/log/development.log +2695 -0
  65. data/test/dummy/log/test.log +152338 -0
  66. data/test/dummy/public/404.html +67 -0
  67. data/test/dummy/public/422.html +67 -0
  68. data/test/dummy/public/500.html +66 -0
  69. data/test/dummy/public/favicon.ico +0 -0
  70. data/test/dummy/test/fixtures/bidules.yml +7 -0
  71. data/test/dummy/test/fixtures/books.yml +9 -0
  72. data/test/dummy/test/fixtures/dictionaries.yml +7 -0
  73. data/test/dummy/test/fixtures/fictions.yml +7 -0
  74. data/test/dummy/test/fixtures/products.yml +7 -0
  75. data/test/dummy/test/models/bidule_test.rb +7 -0
  76. data/test/dummy/test/models/book_test.rb +7 -0
  77. data/test/dummy/test/models/dictionary_test.rb +7 -0
  78. data/test/dummy/test/models/fiction_test.rb +7 -0
  79. data/test/dummy/test/models/product_test.rb +7 -0
  80. data/test/model_test.rb +34 -0
  81. data/test/retrieving_methods_test.rb +153 -0
  82. data/test/root_instance_methods_test.rb +27 -0
  83. data/test/test_helper.rb +60 -0
  84. metadata +227 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d8e70049fb3abef0baa93d5e1c89e5ca2272cb4
4
+ data.tar.gz: fdef4f7bf35e8fa1d57b2f0b458f931375eb3bf9
5
+ SHA512:
6
+ metadata.gz: 0a6fab3629ac0c6b7fd3c19badefe18c9354ebb9c3071fc5d714616bade91000289eedfcce376bbac372ccecaed473c80e91400411798ab52d02fcd9c0118ae6
7
+ data.tar.gz: 7e056a783abbd3827b4a5cbc5440288f61be57bf4f5595759650b43a508ce0483aceed1aead49a61bc625fe208369983b52a05b04b65ecf4a82c36969c56c434
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = Citier4
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Citier4'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
@@ -0,0 +1,95 @@
1
+
2
+ module Citier4
3
+ module ActsAsCitier4
4
+
5
+ citier_debug("Including Citier ActAsCitier4")
6
+
7
+ # your code will go here
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ citier_debug("ActAsCitier included")
12
+ end
13
+
14
+ def self.included(base)
15
+ # When a class includes a module the module’s self.included method will be invoked.
16
+ # base.send :extend, Citier4::ClassMethods
17
+ end
18
+
19
+ module ClassMethods
20
+ @@first_call=true
21
+
22
+ def acts_as_citier4(options = {})
23
+ # your code will go here
24
+ # First call, in the root class, then in a child, then in a child of child, etc ...
25
+
26
+ set_acts_as_citier(true)
27
+
28
+ # SomesOptions are authorize only in root class, not in child
29
+ # but is_root? is not yet implemented
30
+ # but due to the inheritance cascade, the first call of "acts_as_citier" is perform in the root class
31
+
32
+ #:table_name = option for setting the name of the current class table_name, default value = 'tableized(current class name)'
33
+ # option table_name is authorised in root and child
34
+
35
+ table_name = (options[:table_name] || self.name.tableize.gsub(/\//,'_')).to_s
36
+
37
+ if @@first_call
38
+ # Unfortunatly, first_call is not a good solution when we are in developpement : acts_as_citier4 could be reload for the root class ...
39
+ # if ! superclass.acts_as_citier?
40
+ # Root class
41
+ # Option for setting the inheritance columns, default value = 'type'
42
+ # authorized only in root
43
+ db_type_field = (options[:db_type_field] || :type).to_s
44
+ puts "DODO : In Citier, we have to verify the presence of inheritance_column : #{db_type_field}"
45
+ self.inheritance_column = "#{db_type_field}"
46
+
47
+ # Option for setting the super_class. Only in root
48
+ # maby it is not usefull any more ? TODO remove super_class
49
+ super_class = (options[:super_class] || ActiveRecord::Base) # add
50
+
51
+ citier_debug("Root Class, in home directory")
52
+ self.table_name = "#{table_name}"
53
+ citier_debug("table_name -> #{self.table_name}")
54
+
55
+ # Add the functions required for root classes only
56
+ # include is for adding methods to an instance of a class
57
+ # extend is for adding class methods.
58
+ send :extend, Citier4::RootClassMethods
59
+ send :include, Citier4::RootInstanceMethods
60
+ else
61
+ citier_debug("In Child Class, not Root Class")
62
+
63
+ # setting the inheritance columns in the child.
64
+ # do we have to do_it ?
65
+ # - in the writeable part ?
66
+ # - in the readable part ?
67
+
68
+ # debugger
69
+ self.inheritance_column = superclass.inheritance_column
70
+
71
+ citier_debug("table_name, writable -> #{table_name}")
72
+ # Set up the table which contains ALL attributes we want for this class
73
+ self.table_name = "view_#{table_name}"
74
+ citier_debug("tablename (view), readable -> #{self.table_name}")
75
+
76
+ # The the Writeable. References the write-able table for the class because
77
+ # save operations etc can't take place on the views
78
+ self.const_set("Writeable", create_class_writable(self))
79
+ # pour access : self.const_get :Writeable
80
+
81
+ after_initialize do
82
+ self.id = nil if self.new_record? && self.id == 0
83
+ end
84
+
85
+ # Add the functions required for children only
86
+ send :include, Citier4::ChildInstanceMethods
87
+ end
88
+ @@first_call = false
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+
95
+ ActiveRecord::Base.send :include, Citier4::ActsAsCitier4
@@ -0,0 +1,111 @@
1
+ module Citier4
2
+ module ChildInstanceMethods
3
+
4
+ citier_debug("Including Citier Child Instance")
5
+
6
+ def save(options={})
7
+ return false if (options[:validate] != false && !self.valid?)
8
+
9
+ #citier_debug("Callback (#{self.inspect})")
10
+ citier_debug("SAVING #{self.class.to_s}")
11
+
12
+ #AIT NOTE: Will change any protected values back to original values so any models onwards won't see changes.
13
+ # Run save and create/update callbacks, just like ActiveRecord does
14
+ self.run_callbacks(:save) do
15
+ self.run_callbacks(self.new_record? ? :create : :update) do
16
+ # debugger
17
+ #ici
18
+ #get the attributes of the class which are inherited from it's parent.
19
+ attributes_for_parent = self.attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }
20
+ changed_attributes_for_parent = self.changed_attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }
21
+
22
+ # Get the attributes of the class which are unique to this class and not inherited.
23
+ attributes_for_current = self.attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }
24
+ changed_attributes_for_current = self.changed_attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }
25
+
26
+ citier_debug("Attributes for #{self.class.superclass.to_s}: #{attributes_for_parent.inspect}")
27
+ citier_debug("Changed attributes for #{self.class.superclass.to_s}: #{changed_attributes_for_parent.keys.inspect}")
28
+ citier_debug("Attributes for #{self.class.to_s}: #{attributes_for_current.inspect}")
29
+ citier_debug("Changed attributes for #{self.class.to_s}: #{changed_attributes_for_current.keys.inspect}")
30
+
31
+ ########
32
+ #
33
+ # Parent saving
34
+
35
+ #create a new instance of the superclass, passing the inherited attributes.
36
+
37
+ #
38
+ parent = self.class.superclass.new
39
+ parent.force_attributes(attributes_for_parent, :merge => true)
40
+ # Ceci ne marche pas : parent = self.class.superclass.new attributes_for_parent
41
+
42
+ changed_attributes_for_parent["id"] = 0 # We need to change at least something to force a timestamps update.
43
+ parent.force_changed_attributes(changed_attributes_for_parent)
44
+
45
+ parent.id = self.id if id
46
+ parent.type = self.type
47
+
48
+ parent.is_new_record(new_record?)
49
+
50
+ # If we're root (AR subclass) this will just be saved as normal through AR. If we're a child it will call this method again.
51
+ # It will try and save it's parent and then save itself through the Writeable constant.
52
+ parent_saved = parent.save
53
+ self.id = parent.id
54
+
55
+ if !parent_saved
56
+ # Couldn't save parent class
57
+ citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
58
+ citier_debug("Errors = #{parent.errors.to_s}")
59
+ return false # Return false and exit run_callbacks :save and :create/:update, so the after_ callback won't run.
60
+ end
61
+
62
+ #End of parent saving
63
+
64
+ ######
65
+ ##
66
+ ## Self Saving
67
+ ##
68
+
69
+ # If there are attributes for the current class (unique & not inherited), save current model
70
+ if !attributes_for_current.empty?
71
+
72
+ current = self.class::Writeable.new
73
+ current.force_attributes(attributes_for_current, :merge => true)
74
+ # marche pas non plus current = self.class::Writeable.new attributes_for_current
75
+
76
+ current.force_changed_attributes(changed_attributes_for_current)
77
+
78
+ current.id = self.id
79
+ current.is_new_record(new_record?)
80
+
81
+ current_saved = current.save
82
+
83
+ current.after_save_change_request if current.respond_to?('after_save_change_request') #Specific to an app I'm building
84
+
85
+ if !current_saved
86
+ citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
87
+ citier_debug("Errors = #{current.errors.to_s}")
88
+ return false # Return false and exit run_callbacks :save and :create/:update, so the after callback won't run.
89
+ end
90
+ end
91
+
92
+ # at this point, parent_saved && current_saved
93
+
94
+ is_new_record(false) # This is no longer a new record
95
+
96
+ self.force_changed_attributes({}) # Reset changed_attributes so future changes will be tracked correctly
97
+
98
+ # No return, because we want the after callback to run.
99
+ end
100
+ end
101
+ return true
102
+ end
103
+
104
+ def save!(options={})
105
+ raise ActiveRecord::RecordInvalid.new(self) if (options[:validate] != false && !self.valid?)
106
+ self.save || raise(ActiveRecord::RecordNotSaved)
107
+ end
108
+
109
+ include InstanceMethods
110
+ end
111
+ end
@@ -0,0 +1,118 @@
1
+ class ActiveRecord::Base
2
+
3
+ citier_debug("Including Citier Core Ext")
4
+
5
+ def self.set_acts_as_citier(citier)
6
+ @acts_as_citier = citier
7
+ end
8
+
9
+ def self.acts_as_citier?
10
+ @acts_as_citier || false
11
+ end
12
+
13
+ def self.[](column_name)
14
+ arel_table[column_name]
15
+ end
16
+
17
+ def is_new_record(state)
18
+ @new_record = state
19
+ end
20
+
21
+ #create the writeable class which inherits from ActiveRecord::Base
22
+ def self.create_class_writable(class_reference)
23
+ Class.new(ActiveRecord::Base) do
24
+ include Citier4::InstanceMethods::ForcedWriters
25
+
26
+ view_name = class_reference.table_name
27
+ # set the name of the table associated to this class
28
+ # this class will be associated to the writable table of the class_reference class
29
+ self.table_name = view_name[5..view_name.length]
30
+ end
31
+ end
32
+ end
33
+
34
+ class ActiveRecord::Migration
35
+ #function for creating views for migrations
36
+ def create_citier_view(theclass)
37
+ # flush any column info in memory
38
+ # Loops through and stops once we've cleaned up to our root class.
39
+ # We MUST user Writeable as that is the place where changes might reside!
40
+ reset_class = theclass::Writeable
41
+ until reset_class == ActiveRecord::Base # Refinery::Core::BaseModel # ActiveRecord::Base eoz
42
+ citier_debug("Resetting column information on #{reset_class}")
43
+ reset_class.reset_column_information
44
+ reset_class = reset_class.superclass
45
+ end
46
+
47
+ self_columns = theclass::Writeable.column_names.select{ |c| c != "id" }
48
+ parent_columns = theclass.superclass.column_names.select{ |c| c != "id" }
49
+ columns = parent_columns+self_columns
50
+ self_read_table = theclass.table_name
51
+ self_write_table = theclass::Writeable.table_name
52
+ parent_read_table = theclass.superclass.table_name
53
+ # sql = "CREATE VIEW #{self_read_table} AS SELECT #{parent_read_table}.id, #{columns.join(',')} FROM #{parent_read_table}, #{self_write_table} WHERE #{parent_read_table}.id = #{self_write_table}.id"
54
+ debugger
55
+ #Use our rails_sql_views gem to create the view so we get it outputted to schema
56
+ create_view "#{self_read_table}", "SELECT #{parent_read_table}.id, #{columns.join(',')} FROM #{parent_read_table}, #{self_write_table} WHERE #{parent_read_table}.id = #{self_write_table}.id" do |v|
57
+ v.column :id
58
+ columns.each do |c|
59
+ v.column c.to_sym
60
+ end
61
+ end
62
+
63
+ # citier_debug("Creating citier view -> #{sql}")
64
+ #theclass.connection.execute sql
65
+
66
+
67
+ end
68
+
69
+ def drop_citier_view(theclass) #function for dropping views for migrations
70
+ self_read_table = theclass.table_name
71
+ # sql = "DROP VIEW #{self_read_table}"
72
+
73
+ drop_view(self_read_table.to_sym) #drop using our rails sql views gem
74
+
75
+ citier_debug("Dropping citier view -> #{sql}")
76
+ #theclass.connection.execute sql
77
+ end
78
+
79
+ def update_citier_view(theclass) #function for updating views for migrations
80
+ citier_debug("Updating citier view for #{theclass}")
81
+ if theclass.table_exists?
82
+ drop_citier_view(theclass)
83
+ create_citier_view(theclass)
84
+ else
85
+ citier_debug("Error: #{theclass} VIEW doesn't exist.")
86
+ end
87
+ end
88
+
89
+ def create_or_update_citier_view(theclass) #Convienience function for updating or creating views for migrations
90
+ citier_debug("Create or Update citier view for #{theclass}")
91
+ if theclass.table_exists?
92
+ update_citier_view(theclass)
93
+ else
94
+ citier_debug("VIEW DIDN'T EXIST. Now creating for #{theclass}")
95
+ create_citier_view(theclass)
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ module ActiveRecord
102
+ # = Active Record Relation
103
+ class Relation
104
+
105
+ # Causes the records to be loaded from the database if they have not
106
+ # been loaded already. You can use this if for some reason you need
107
+ # to explicitly load some records before actually using them. The
108
+ # return value is the relation itself, not the records.
109
+ #
110
+ # Post.where(published: true).load # => #<ActiveRecord::Relation>
111
+ def load
112
+ puts "in load de citier4"
113
+ exec_queries unless loaded?
114
+
115
+ self
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,41 @@
1
+ module Citier4
2
+ module InstanceMethods
3
+ def self.included(base)
4
+ base.send :include, ForcedWriters
5
+ end
6
+
7
+ module ForcedWriters
8
+ def force_attributes(new_attributes, options = {})
9
+ # debugger
10
+ # TODO new_attributes = @attributes.merge(new_attributes) if options[:merge]
11
+ new_attributes = self.attributes.merge(new_attributes) if options[:merge]
12
+
13
+ # TODO @attributes = new_attributes
14
+ self.attributes = new_attributes
15
+
16
+ if options[:clear_caches] != false
17
+ @aggregation_cache = {}
18
+ @association_cache = {}
19
+ @attributes_cache = {}
20
+ end
21
+ end
22
+
23
+ def force_changed_attributes(new_changed_attributes, options = {})
24
+ new_changed_attributes = @attributes.merge(new_changed_attributes) if options[:merge]
25
+ @changed_attributes = new_changed_attributes
26
+ end
27
+ end
28
+
29
+ # USAGE validates :attribute, :citier_uniqueness => true
30
+ # Needed because validates :attribute, :uniqueness => true Won't work because it tries to call child_class.attribute on parents table
31
+ class CitierUniquenessValidator < ActiveModel::EachValidator
32
+ def validate_each(object, attribute, value)
33
+ existing_record = object.class.where(attribute.to_sym => value).limit(1).first
34
+ if existing_record && existing_record.as_root != object.as_root #if prev record exist and it isn't our current obj
35
+ object.errors[attribute] << (options[:message] || "has already been taken.")
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,139 @@
1
+ module ActiveRecord
2
+ class Relation
3
+
4
+
5
+ # instance.delete -> class.delete(id) -> class.where(id).delete_all
6
+ # donc tout finit dans delete_all
7
+
8
+ citier_debug("Including Citier Relation")
9
+
10
+ # http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-delete
11
+ # delete_all(conditions = nil))
12
+ # Deletes the records matching conditions without instantiating the records first,
13
+ # and hence not calling the destroy method nor invoking callbacks.
14
+ # This is a single SQL DELETE statement that goes straight to the database,
15
+ # much more efficient than destroy_all.
16
+ # Be careful with relations though, in particular :dependent rules defined on associations
17
+ # are not honored. Returns the number of rows affected.
18
+
19
+ alias_method :relation_delete_all, :delete_all
20
+
21
+ def delete_all(conditions = nil)
22
+
23
+ return relation_delete_all(conditions) if !@klass.acts_as_citier?
24
+ return relation_delete_all(conditions) if conditions
25
+
26
+ deleted = true
27
+ ids = nil
28
+ c = @klass
29
+
30
+ bind_values.each do |bind_value|
31
+ if bind_value[0].name == "id"
32
+ ids = bind_value[1]
33
+ break
34
+ end
35
+ end
36
+
37
+ ids ||= where_values_hash["id"] || where_values_hash[:id]
38
+ where_hash = ids ? { :id => ids } : nil
39
+
40
+ # debugger
41
+
42
+
43
+ # ici, si on a un dictionaire avec id 10
44
+ # Product.delete 10
45
+ # Book.delete 10
46
+ # Dictionary.delete 10
47
+ # ne vont pas faire la meme chose.
48
+ # Avec Product.delete 10, les Book::Writeable et Dictionary::Writeable ne sont pas déleter pour l'ID 10
49
+ # il faudrait pouvoir attaquer la boucle avec c = Dictionary et pas c = Product
50
+
51
+ # ne marche que si on a que un ids et pas un tableau d'ids ...
52
+ if ids.class == Fixnum
53
+ # debugger
54
+ c = @klass.find(ids).class
55
+ end
56
+
57
+ deleted &= c.base_class.where(where_hash).relation_delete_all
58
+
59
+ while c.superclass != ActiveRecord::Base # Refinery::Core::BaseModel # eoz ActiveRecord::Base
60
+ if c.const_defined?(:Writeable)
61
+ citier_debug("Deleting back up hierarchy #{c}")
62
+ deleted &= c::Writeable.where(where_hash).delete_all
63
+ end
64
+ c = c.superclass
65
+ end
66
+
67
+ deleted
68
+ end
69
+
70
+ # TODO : remove to_a ..., will be obsolete ? and doen't work with rails 4.2 (ok for 4.1)
71
+ # to_a :
72
+ # Returns an array representation of obj. For objects of class Object and others that don’t explicitly override the method,
73
+ # the return value is an array containing self. However, this latter behavior will soon be obsolete.
74
+
75
+ alias_method :relation_to_a, :to_a
76
+ def to_a
77
+ citier_debug("citier -> to_a")
78
+ return relation_to_a if !@klass.acts_as_citier?
79
+ records = relation_to_a
80
+
81
+ c = @klass
82
+
83
+ if records.all? { |record| record.class == c }
84
+ return records
85
+ end
86
+
87
+ full_records = []
88
+ ids_wanted = {}
89
+
90
+ # Map all the ids wanted per type
91
+ records.each do |record|
92
+ if record.class == c # We don't need to find the record again if this is already the correct one
93
+ full_records << record
94
+ next
95
+ end
96
+
97
+ ids_wanted[record.class] ||= []
98
+ ids_wanted[record.class] << record.id
99
+ end
100
+
101
+ # Find all wanted records
102
+ ids_wanted.each do |type_class, ids|
103
+ full_records.push(*type_class.find(ids))
104
+ end
105
+
106
+ # Make a new array with the found records at the right places
107
+ records.each do |record|
108
+ full_record = full_records.find { |full_record| full_record.id == record.id }
109
+ # debugger
110
+ att = full_record.instance_variable_get(:@attributes)
111
+ record.force_attributes(att, :merge => true, :clear_caches => false)
112
+ # TODO record.force_attributes(full_record.instance_variable_get(:@attributes), :merge => true, :clear_caches => false)
113
+ end
114
+
115
+ return records
116
+ end
117
+
118
+ # TODO
119
+ # apply_finder_options is depreciated in rails 4
120
+ # use by paginate
121
+ # TODO test page
122
+ # alias_method :relation_apply_finder_options, :apply_finder_options
123
+ # def apply_finder_options(options)
124
+ # return relation_apply_finder_options(options) if !@klass.acts_as_citier?
125
+ # relation = self
126
+ # # With option :no_children set to true, only records of type self will be returned.
127
+ # # So Root.all(:no_children => true) won't return Child records.
128
+ # no_children = options.delete(:no_children)
129
+ # if no_children
130
+ # relation = clone
131
+ # c = @klass
132
+ # self_type = c.superclass == ActiveRecord::Base ? nil : c.name
133
+ # relation = relation.where(:type => self_type)
134
+ # end
135
+ # relation.relation_apply_finder_options(options)
136
+ # end
137
+
138
+ end
139
+ end
@@ -0,0 +1,36 @@
1
+ module Citier4
2
+ module RootClassMethods
3
+
4
+ citier_debug("Including Citier Class Methods")
5
+
6
+ # any method placed here will apply to classes
7
+ # remove the acts_as_citier definition. see file acts_as_citer
8
+ # def acts_as_citier(options = {})
9
+ # ...
10
+ # end
11
+ #def acts_as_citier?
12
+ # true
13
+ # end
14
+
15
+
16
+
17
+ # find_by and find_by! are exaclty the same defintion that ActiveRecord::FinderMethods
18
+ # see finder_methods.rb
19
+ # but it is not these function that are call by
20
+ # Post.find_by name: 'Spartacus', rating: 4
21
+ # but the one that are define in ActiveRecord::Core
22
+ # So, theses methods are here just to overwrite the one in ActiveRecord::Core
23
+ def find_by(*args)
24
+ where(*args).take
25
+ rescue RangeError
26
+ nil
27
+ end
28
+ def find_by!(*args)
29
+ where(*args).take!
30
+ rescue RangeError
31
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
32
+ end
33
+
34
+
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ module Citier4
2
+ module RootInstanceMethods
3
+
4
+ citier_debug("Including Citier Root")
5
+
6
+ include InstanceMethods
7
+
8
+ # Instantiates the instance as it's lowest root class. Used when destroying a root class to
9
+ # make sure we're not leaving children behind
10
+ def as_child
11
+ #instance_class = Object.const_get(self.type)
12
+ return bottom_class_instance = Kernel.const_get(self.type).where(:id => self.id).first
13
+ end
14
+
15
+ # Access the root class if ever you need.
16
+ def as_root
17
+ if !self.is_root?
18
+ root_class = self.class.base_class
19
+
20
+ #get the attributes of the class which are inherited from it's parent.
21
+ attributes_for_parent = self.attributes.reject{|key,value| !root_class.column_names.include?(key) }
22
+
23
+ #create a new instance of the superclass, passing the inherited attributes.
24
+ parent = root_class.new(attributes_for_parent)
25
+ parent.id = self.id
26
+ parent.type = self.type
27
+
28
+ parent.is_new_record(new_record?)
29
+
30
+ parent
31
+ else
32
+ self #just return self if we are the root
33
+ end
34
+ end
35
+
36
+ #For testing whther we are using the framework or not
37
+ def acts_as_citier?
38
+ true
39
+ end
40
+
41
+ def is_root?
42
+ self.class.superclass==ActiveRecord::Base # eoz
43
+ # self.class.superclass==Refinery::Core::BaseModel
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module Citier4
2
+ VERSION = "0.0.1"
3
+ end