easy_exports 0.1.0 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9e4470d18b361781bf745a2ca0dc563b82ccf603b456a55ad75a96113d3975c
4
- data.tar.gz: 2576218f1f50c7743f1ef0a9cbada4e4ebe452f20dfb12dec4613aedcb0f23d4
3
+ metadata.gz: ed1cc375db87028330d34ded26b7e247a1ff4382267254118e06b994d5ae66d6
4
+ data.tar.gz: 4529a792f705691f04ea2b707a00503866d324ca2388bb5587ffd61563a8f98c
5
5
  SHA512:
6
- metadata.gz: 401cf20c2ee26d378b6f31d02acb64e34bf49761c417f65e0954d9132f45855feb8fcc13be73948cbdbb5e1b941df1e30363a23828ed14bdec8601e1a13c4309
7
- data.tar.gz: 2c5e04b944b9551843802c46ce131f5d0c7ff0e732d1db1f3fc07ef93a9e2227b67771e3a287da54b123d8b4e254e20206e41b9f8a70728cf79f4a3d287fb835
6
+ metadata.gz: c5ca2b24a5a23f685d04dfd020cff2dea3bab1d550f40c1467cfbc04608cfaf701bd69fd6eb91652a1f4ede40f8608fee8f87ac4bd22ff3742155b7238f19eab
7
+ data.tar.gz: 565ddc57bd713f6097aad5717ddb9c95d39fc18d7e3a5db2a81b5d489098c0fdf17723b7b83d9b018f25ef88c6ecb7edebfc7c364fb6aa1b5add5ae7db80ad5c
data/README.md CHANGED
@@ -1,8 +1,5 @@
1
1
  # EasyExports
2
- Short description and motivation.
3
-
4
- ## Usage
5
- How to use my plugin.
2
+ EasyExports is a rails ActiveRecord ORM extension dedicated to streamlining and simplifying the model data export process by eliminating common complexities.
6
3
 
7
4
  ## Installation
8
5
  Add this line to your application's Gemfile:
@@ -20,9 +17,211 @@ Or install it yourself as:
20
17
  ```bash
21
18
  $ gem install easy_exports
22
19
  ```
20
+ ## Usage
21
+ Upon installation, EasyExports seamlessly integrates with ```ActiveRecord::Base```, granting all models immediate access to its efficient export methods.
22
+
23
+ ### Generating Exportable Attributes
24
+
25
+ Retrieve exportable attributes using the `exportable_attributes` method. This method retrieves attributes of the model itself and those of all its associations.
26
+
27
+ ```ruby
28
+ # Example Models and Exportable Attributes
29
+
30
+ # User model with columns: first_name, last_name, created_at, updated_at
31
+ class User < ApplicationRecord
32
+ has_and_belongs_to_many :emails
33
+ has_many :phones
34
+ end
35
+
36
+ # Exportable attributes for the User model
37
+ User.exportable_attributes
38
+ # =>
39
+ # {
40
+ # "User" => ["id", "first name", "last name", "created at", "updated at"],
41
+ # "Emails" => ["id", "address", "created at", "updated at"],
42
+ # "Phones" => ["id", "number", "user id", "created at", "updated at"]
43
+ # }
44
+
45
+ # Phone model with columns: number, user_id, created_at, updated_at
46
+ class Phone < ApplicationRecord
47
+ belongs_to :user
48
+ end
49
+
50
+ # Exportable attributes for the Phone model
51
+ Phone.exportable_attributes
52
+ # =>
53
+ # {
54
+ # "Phone" => ["id", "number", "user id", "created at", "updated at"],
55
+ # "User" => ["id", "first name", "last name", "created at", "updated at"]
56
+ # }
57
+ ```
58
+
59
+ ### Generating Exports from Exportable Attributes
60
+
61
+ To generate exports, use the `generate_exports(exportable_attributes, ids)` method.
62
+
63
+ - The `exportable_attributes` argument specifies the chosen attributes from the exportable attributes list.
64
+ - The `ids` argument is optional; provide IDs to export data for specific records.
65
+ - Omitting `ids` will trigger exports for all records of the given model.
66
+
67
+ The method returns an `EasyExports::Export` object containing hash data from the records and a `csv_string` that can be written to a CSV file.
68
+
69
+ ```ruby
70
+ user_exportable_attributes = {"User"=>["id", "first name"], "Phones"=>["id", "number"], "Emails"=>["id", "address"]}
71
+
72
+ exports_object = User.generate_exports(user_exportable_attributes)
73
+ # => EasyExports::Export(Object)
74
+
75
+ exports_data = exports_object.data
76
+ # =>
77
+ # [
78
+ # {"user_id"=>1, "user_first_name"=>"Sydney", "phones_id"=>1, "phones_number"=>"(473) 693-8745", "emails_id"=>5, "emails_address"=>"blake_armstrong@bahringer.test"},
79
+ # {"user_id"=>1, "user_first_name"=>"Sydney", "phones_id"=>2, "phones_number"=>"594-299-0722", "emails_id"=>6, "emails_address"=>"dulce@mertz.example"},
80
+ # {"user_id"=>1, "user_first_name"=>"Sydney", "phones_id"=>3, "phones_number"=>"1-609-662-2028", "emails_id"=>nil, "emails_address"=>nil},
81
+ # {"user_id"=>2, "user_first_name"=>"Stan", "phones_id"=>4, "phones_number"=>"951-671-9548", "emails_id"=>7, "emails_address"=>"dominick@durgan.example"},
82
+ # {"user_id"=>2, "user_first_name"=>"Stan", "phones_id"=>5, "phones_number"=>"1-698-432-7489", "emails_id"=>nil, "emails_address"=>nil}
83
+ # ]
84
+
85
+ exports_csv_string = exports_object.csv_string
86
+ # =>
87
+ # "user_id,user_first_name,phones_id,phones_number,emails_id,emails_address\n
88
+ # 1,Sydney,1,(473) 693-8745,5,blake_armstrong@bahringer.test\n
89
+ # 1,Sydney,2,594-299-0722,6,dulce@mertz.example\n
90
+ # 1,Sydney,3,1-609-662-2028,,\n
91
+ # 2,Stan,4,951-671-9548,7,dominick@durgan.example\n
92
+ # 2,Stan,5,1-698-432-7489,,\n"
93
+
94
+ # Writing csv_string to a file to visualize the generated export
95
+ File.open(file_path, 'w') do |file|
96
+ file.write(exports_csv_string)
97
+ end
98
+ ```
99
+ <div align="center">
100
+ <img width="600" alt="csv_with_emails" src="https://github.com/SydDaps/easy_exports/assets/51008616/8b9df43c-419d-4ca0-8cb1-6217025b8050">
101
+ </div>
102
+
103
+ Exported CSV showcases data for:
104
+
105
+ - User "Sydney" with 3 phones and 2 emails
106
+ - User "Stan" with 2 phones and 1 email.
107
+ - The main CSV header includes association names and attribute names.
108
+
109
+
110
+ ### Exportable Attributes Aliases
111
+
112
+ Configure an alternative association name for exportable attributes using the `exportable_association_aliases(aliases)` model method.
113
+
114
+ - Invoke this method below all association definitions.
115
+ - `aliases` should be a hash in the pattern: `{valid_association_name or model_name: "alternative_name"}`.
116
+ - Ensure all hash arguments are snake-cased.
117
+
118
+ ```ruby
119
+ # Example Model with exportable_association_aliases
120
+
121
+ # User model with columns: first_name, last_name, created_at, updated_at
122
+ class User < ApplicationRecord
123
+ has_many :phones
124
+
125
+ exportable_association_aliases phones: :mobile_phones
126
+ end
127
+
128
+ # Exportable attributes for the User model will now be
129
+ User.exportable_attributes
130
+ # =>
131
+ # {
132
+ # "User" => ["id", "first name", "last name", "created at", "updated at"],
133
+ # "Mobile phones" => ["id", "number", "user id", "created at", "updated at"]
134
+ # }
135
+ ```
136
+ With the exportable_association_aliases configured, the phones association has been renamed to "Mobile phones". This new name will appear in the export header when generating exports with this alias for exportable attributes.
137
+
138
+ ### Excluding Specific Exportable Attributes
139
+
140
+ Configure associations to exclude certain attributes from exportable attributes using the `exclude_exportable_attributes(association_attributes)` model method.
141
+
142
+ - Invoke this method below all association declarations.
143
+ - `association_attributes` should follow the pattern `{valid_association_name or model_name: [valid_attributes_to_remove]}`.
144
+ - For removing attributes across all associations and the model itself, use the "all" key as the association_name.
145
+
146
+ ```ruby
147
+ # Example Model with exclude_exportable_attributes
148
+
149
+ # User model with columns: first_name, last_name, created_at, updated_at
150
+ class User < ApplicationRecord
151
+ has_many :phones
152
+
153
+ exclude_exportable_attributes all: [:id], user: [:last_name], phones: [:user_id]
154
+ end
155
+
156
+ # Exportable attributes for the User model will now be
157
+ User.exportable_attributes
158
+ # =>
159
+ # {
160
+ # "User" => ["first name", "created at", "updated at"],
161
+ # "Phones" => ["number", "created at", "updated at"]
162
+ # }
163
+ ```
164
+ In this example, note that:
165
+ - All associations exclude the id attribute.
166
+ - The User model excludes the last_name attribute.
167
+ - The Phones association excludes the user_id attribute.
168
+
169
+
170
+ ### Excluding Specific Exportable Attribute Associations
171
+
172
+ Configure model's exportable attributes to exclude certain associations using the `associations_to_exclude(associations)` model method.
173
+
174
+ - Apply this method below all association declarations.
175
+ - `associations` should follow the pattern `['association_name']`.
23
176
 
24
- ## Contributing
25
- Contribution directions go here.
177
+ ```ruby
178
+ # Example Model with associations_to_exclude
179
+
180
+ # User model with columns: first_name, last_name, created_at, updated_at
181
+ class User < ApplicationRecord
182
+ has_many :phones
183
+
184
+ associations_to_exclude [:phones]
185
+ end
186
+
187
+ # Exportable attributes for the User model will now be
188
+ User.exportable_attributes
189
+ # =>
190
+ # {
191
+ # "User" => ["id", "first name", "last name", "created at", "updated at"]
192
+ # }
193
+ ```
194
+ In this example, the attributes of the phones association are excluded from the exportable attributes of the User model.
195
+
196
+
197
+ ### Adding Custom Attribute to Exportable Attributes
198
+
199
+ Leverage a handy Rails method to transform a model instance method into an attribute, incorporating it into the exportable attributes.
200
+
201
+ ```ruby
202
+ # Example Model with Custom Virtual Attribute
203
+
204
+ # User model with columns: first_name, last_name, created_at, updated_at
205
+ class User < ApplicationRecord
206
+ attribute :total_number_of_phones
207
+
208
+ has_many :phones
209
+
210
+ associations_to_exclude [:phones]
211
+
212
+ def total_number_of_phones
213
+ phones.size
214
+ end
215
+ end
216
+
217
+ # Exportable attributes for the User model will now include
218
+ User.exportable_attributes
219
+ # =>
220
+ # {
221
+ # "User" => ["id", "first name", "last name", "created at", "updated at", "total number of phones"]
222
+ # }
223
+ ```
224
+ In this example, the custom attribute "total number of phones" has been seamlessly integrated into the exportable attributes, showcasing the flexibility of Rails' capabilities.
26
225
 
27
226
  ## License
28
227
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasyExports
4
+ module DataAttributesResolver
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ private
9
+
10
+ def value_from_selected_attributes(selected_attributes, record, export_row_template)
11
+ selected_attributes.each_with_object([export_row_template]) do |(association_name, attributes), export_rows|
12
+ objects = objects_for_attribute(association_name, record)
13
+
14
+ attributes.each do |attribute|
15
+ attribute_values = resolve_attributes(attribute, objects)
16
+
17
+ attribute_values.each_with_index do |value, index|
18
+ export_column = export_rows[index] || export_row_template
19
+
20
+ export_rows[index] = export_column.merge(export_header(association_name, attribute) => value)
21
+ end
22
+ end
23
+
24
+ export_row_template.merge!(export_rows.first) if association_name == underscored_self_name
25
+ end
26
+ end
27
+
28
+ def resolve_attributes(attribute, objects)
29
+ objects.empty? ? [nil] : objects.map { |object| parse_attribute_value(object.send(attribute)) }.flatten
30
+ end
31
+
32
+ def parse_attribute_value(value)
33
+ return DateTime.parse(value.to_s).strftime('%Y-%m-%d %H:%M:%S') if value.is_a?(ActiveSupport::TimeWithZone)
34
+
35
+ return "'#{value}" if value.is_a?(String) && value&.start_with?('0')
36
+
37
+ value
38
+ end
39
+
40
+ def objects_for_attribute(association_name, record)
41
+ object = association_name == underscored_self_name ? record : record.send(association_name)
42
+ object.respond_to?(:each) ? object : [object].compact
43
+ end
44
+
45
+ def export_header(association_name, attribute)
46
+ association_alias = associations_aliases_store[underscored_self_name]
47
+ association_alias = association_alias.blank? ? nil : association_alias[association_name]
48
+
49
+ "#{association_alias || association_name}_#{attribute}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasyExports
4
+ module DataLoader
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ private
9
+
10
+ def fetch_records(ids, selected_attributes)
11
+ validate_association_attributes(selected_attributes, 'to_exported_data')
12
+
13
+ records_with_preloaded_associations(ids, selected_attributes)
14
+ end
15
+
16
+ def association_attributes(association_name)
17
+ association_name = if association_name == underscored_self_name
18
+ association_name.classify
19
+ else
20
+ reflect_on_all_associations.find do |association|
21
+ association.name.to_s == association_name
22
+ end&.class_name
23
+ end
24
+
25
+ association_name.constantize.attribute_names
26
+ end
27
+
28
+ def records_with_preloaded_associations(ids, selected_attributes)
29
+ records = ids.blank? ? all : where(id: ids)
30
+
31
+ associations_to_preload = selected_attributes.keys
32
+ associations_to_preload.delete(underscored_self_name)
33
+
34
+ ActiveRecord::Associations::Preloader.new(
35
+ records: records,
36
+ associations: associations_to_preload
37
+ ).call
38
+
39
+ records
40
+ end
41
+ end
42
+ end
43
+ end
@@ -50,6 +50,4 @@ module EasyExports
50
50
  end
51
51
  end
52
52
  end
53
- end
54
-
55
- ActiveRecord::Base.include EasyExports::ExcludeExportableAttributesConfigurations
53
+ end
@@ -42,4 +42,4 @@ module EasyExports
42
42
  end
43
43
  end
44
44
 
45
- ActiveRecord::Base.include EasyExports::ExportableAssociationAliasesConfigurations
45
+ # ActiveRecord::Base.include EasyExports::ExportableAssociationAliasesConfigurations
@@ -32,5 +32,3 @@ module EasyExports
32
32
  end
33
33
  end
34
34
  end
35
-
36
- ActiveRecord::Base.include EasyExports::ExportableAttributeResolvers
@@ -4,11 +4,19 @@ module EasyExports
4
4
  module ExportableAttributes
5
5
  extend ActiveSupport::Concern
6
6
 
7
- class_methods do
7
+ included do
8
8
  cattr_accessor :excluded_exportable_attributes_store, default: {}, instance_writer: false
9
9
  cattr_accessor :associations_aliases_store, default: {}, instance_writer: false
10
10
  cattr_accessor :associations_to_exclude_store, default: {}, instance_writer: false
11
+ #TODO: cache attributes(make option)
12
+
13
+ include EasyExports::ExportableAssociationAliasesConfigurations
14
+ include EasyExports::ExportableAttributeResolvers
15
+ include EasyExports::ExcludeExportableAttributesConfigurations
16
+ include EasyExports::ExportsGenerable
17
+ end
11
18
 
19
+ class_methods do
12
20
  def exportable_attributes
13
21
  self_with_associations.each_with_object({}) do |association, attributes|
14
22
  association_name = association.name.to_s.downcase
@@ -41,7 +49,7 @@ module EasyExports
41
49
  end
42
50
 
43
51
  def humanize_attribute_names(attributes)
44
- attributes.map { |attribute| attribute.humanize(keep_id_suffix: true).downcase }
52
+ attributes.map { |attribute| attribute.humanize(keep_id_suffix: true).downcase }.sort
45
53
  end
46
54
  end
47
55
  end
@@ -4,18 +4,25 @@ module EasyExports
4
4
  module ExportsGenerable
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ included do
8
+ include EasyExports::DataLoader
9
+ include EasyExports::DataAttributesResolver
10
+ end
11
+
7
12
  class_methods do
8
13
  def generate_exports(fields_to_export = {}, ids = [])
9
14
  validate_exclude_exportable_attributes_argument(fields_to_export, 'generate_exports')
10
15
 
11
16
  selected_exportable_attributes = revert_transformed_names(fields_to_export)
17
+ selected_exportable_attributes = rearrange_selected_attributes(selected_exportable_attributes)
18
+
12
19
  export_row_template = generate_export_row_template(selected_exportable_attributes)
13
20
 
14
21
  selected_attributes = revert_exportable_attributes_aliases(selected_exportable_attributes)
15
22
  records = fetch_records(ids, selected_attributes)
16
23
 
17
24
  exported_data = records.each_with_object([]) do |record, hash_to_export|
18
- hash_to_export << value_from_selected_attributes(selected_attributes, record, export_row_template)
25
+ hash_to_export << value_from_selected_attributes(selected_attributes, record, export_row_template.dup)
19
26
  end.flatten
20
27
 
21
28
  csv_string = write_exported_data_to_csv(exported_data, export_row_template)
@@ -33,90 +40,31 @@ module EasyExports
33
40
  end
34
41
  end
35
42
 
36
- def generate_export_row_template(selected_attributes)
37
- selected_attributes.each_with_object({}) do |(association_name, attributes), export_row|
38
- attributes.each do |attribute|
39
- export_row.merge!("#{association_name}_#{attribute}" => nil)
40
- end
41
- end
42
- end
43
+ def rearrange_selected_attributes(selected_attributes)
44
+ selected_attributes = selected_attributes.to_a
45
+ self_alias_name = associations_aliases_store[underscored_self_name]&.fetch(underscored_self_name, nil)
46
+ self_name = self_alias_name || underscored_self_name
43
47
 
44
- def fetch_records(ids, selected_attributes)
45
- validate_association_attributes(selected_attributes, 'to_exported_data')
46
-
47
- records_with_preloaded_associations(ids, selected_attributes)
48
- end
49
-
50
- def association_attributes(association_name)
51
- association_name = if association_name == underscored_self_name
52
- association_name.classify
53
- else
54
- reflect_on_all_associations.find do |association|
55
- association.name.to_s == association_name
56
- end&.class_name
57
- end
58
-
59
- association_name.constantize.attribute_names
60
- end
61
-
62
- def records_with_preloaded_associations(ids, selected_attributes)
63
- records = ids.blank? ? all : where(id: ids)
64
-
65
- associations_to_preload = selected_attributes.keys
66
- associations_to_preload.delete(underscored_self_name)
48
+ self_exportable_attributes = selected_attributes.find do |selected_attribute|
49
+ selected_attribute.first == self_name
50
+ end
67
51
 
68
- ActiveRecord::Associations::Preloader.new(
69
- records: records,
70
- associations: associations_to_preload
71
- ).call
52
+ if self_exportable_attributes.blank? || selected_attributes[0] == self_exportable_attributes
53
+ return selected_attributes.to_h
54
+ end
72
55
 
73
- records
56
+ selected_attributes.delete(self_exportable_attributes)
57
+ selected_attributes.unshift(self_exportable_attributes).to_h
74
58
  end
75
59
 
76
- def value_from_selected_attributes(selected_attributes, record, export_row_template)
77
- selected_attributes.each_with_object([export_row_template]) do |(association_name, attributes), export_rows|
78
- objects = objects_for_attribute(association_name, record)
79
-
60
+ def generate_export_row_template(selected_attributes)
61
+ selected_attributes.each_with_object({}) do |(association_name, attributes), export_row|
80
62
  attributes.each do |attribute|
81
- attribute_values = resolve_attributes(attribute, objects)
82
-
83
- attribute_values.each_with_index do |value, index|
84
- export_column = export_rows[index] || export_row_template
85
-
86
- export_rows[index] = export_column.merge(export_header(association_name, attribute) => value)
87
- end
63
+ export_row.merge!("#{association_name}_#{attribute}" => nil)
88
64
  end
89
65
  end
90
66
  end
91
67
 
92
- def export_header(association_name, attribute)
93
- association_alias = associations_aliases_store[underscored_self_name]
94
- association_alias = association_alias.blank? ? nil : association_alias[association_name]
95
-
96
- "#{association_alias || association_name}_#{attribute}"
97
- end
98
-
99
- def resolve_attributes(attribute, objects)
100
- objects.empty? ? [nil] : objects.map { |object| parse_attribute_value(object.send(attribute)) }.flatten
101
- end
102
-
103
- def parse_attribute_value(value)
104
- value_class = value.class
105
-
106
- if value_class.eql?(ActiveSupport::TimeWithZone)
107
- DateTime.parse(value.to_s).strftime('%Y-%m-%d %H:%M:%S')
108
- elsif !value_class.eql?(String)
109
- value
110
- else
111
- value.start_with?('0') ? "'#{value}" : value
112
- end
113
- end
114
-
115
- def objects_for_attribute(association_name, record)
116
- object = association_name == underscored_self_name ? record : record.send(association_name)
117
- object.respond_to?(:each) ? object : [object].compact
118
- end
119
-
120
68
  def revert_exportable_attributes_aliases(attributes_with_aliases)
121
69
  attributes_with_aliases.transform_keys { |key| reversed_associations_name_aliases[key] || key }
122
70
  end
@@ -138,5 +86,3 @@ module EasyExports
138
86
  end
139
87
  end
140
88
  end
141
-
142
- ActiveRecord::Base.include EasyExports::ExportsGenerable
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyExports
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/easy_exports.rb CHANGED
@@ -2,14 +2,12 @@
2
2
 
3
3
  require 'easy_exports/version'
4
4
  require 'easy_exports/railtie'
5
- require 'easy_exports/exportable_attributes'
6
5
  require 'easy_exports/exportable_attribute_resolvers'
7
6
  require 'easy_exports/exclude_associations_configurations'
8
7
  require 'easy_exports/exclude_exportable_attributes_configurations'
9
8
  require 'easy_exports/exportable_association_aliases_configurations'
10
- require 'easy_exports/exports_generable'
11
9
  require 'easy_exports/export'
12
-
13
- module EasyExports
14
- # Your code goes here...
15
- end
10
+ require 'easy_exports/data_loader'
11
+ require 'easy_exports/data_attributes_resolver'
12
+ require 'easy_exports/exports_generable'
13
+ require 'easy_exports/exportable_attributes'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_exports
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dapilah Sydney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-16 00:00:00.000000000 Z
11
+ date: 2023-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -106,6 +106,8 @@ files:
106
106
  - README.md
107
107
  - Rakefile
108
108
  - lib/easy_exports.rb
109
+ - lib/easy_exports/data_attributes_resolver.rb
110
+ - lib/easy_exports/data_loader.rb
109
111
  - lib/easy_exports/exclude_associations_configurations.rb
110
112
  - lib/easy_exports/exclude_exportable_attributes_configurations.rb
111
113
  - lib/easy_exports/export.rb