releaf-content 0.2.1 → 1.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.
- checksums.yaml +4 -4
- data/LICENSE +19 -21
- data/app/assets/javascripts/{releaf/controllers → controllers}/releaf/content/nodes.js +0 -0
- data/app/assets/stylesheets/{releaf/controllers → controllers}/releaf/content/nodes.scss +0 -0
- data/app/builders/releaf/content/builders/action_dialog.rb +9 -1
- data/app/builders/releaf/content/builders/tree.rb +1 -1
- data/app/builders/releaf/content/content_type_dialog_builder.rb +2 -2
- data/app/builders/releaf/content/nodes/form_builder.rb +3 -3
- data/app/builders/releaf/content/nodes/index_builder.rb +1 -1
- data/app/builders/releaf/content/nodes/toolbox_builder.rb +0 -5
- data/app/controllers/releaf/content/nodes_controller.rb +109 -129
- data/app/middleware/releaf/content/routes_reloader.rb +12 -4
- data/app/services/releaf/content/node/copy.rb +90 -0
- data/app/services/releaf/content/node/move.rb +21 -0
- data/app/services/releaf/content/node/save_under_parent.rb +22 -0
- data/app/services/releaf/content/node/service.rb +17 -0
- data/app/validators/releaf/content/node/singleness_validator.rb +1 -24
- data/lib/releaf-content.rb +85 -6
- data/lib/releaf/content/acts_as_node.rb +0 -5
- data/lib/releaf/content/acts_as_node/active_record/acts/node.rb +2 -8
- data/lib/releaf/content/configuration.rb +61 -0
- data/lib/releaf/content/engine.rb +1 -34
- data/lib/releaf/content/node.rb +30 -101
- data/lib/releaf/content/node_mapper.rb +28 -2
- data/lib/releaf/content/route.rb +37 -25
- data/spec/builders/content/nodes/action_dialog_spec.rb +39 -0
- data/spec/builders/content/nodes/form_builder_spec.rb +47 -3
- data/spec/builders/content/nodes/toolbox_builder_spec.rb +1 -32
- data/spec/controllers/releaf/content/nodes_controller_spec.rb +42 -11
- data/spec/features/nodes_services_spec.rb +207 -0
- data/spec/features/nodes_spec.rb +328 -30
- data/spec/lib/releaf/content/acts_as_node_spec.rb +4 -32
- data/spec/lib/releaf/content/configuration_spec.rb +159 -0
- data/spec/lib/releaf/content/engine_spec.rb +149 -0
- data/spec/lib/releaf/content/node_spec.rb +66 -324
- data/spec/lib/releaf/content/route_spec.rb +223 -34
- data/spec/middleware/routes_reloader_spec.rb +62 -14
- data/spec/routing/node_mapper_spec.rb +223 -55
- data/spec/services/releaf/content/node/copy_spec.rb +115 -0
- data/spec/services/releaf/content/node/move_spec.rb +20 -0
- data/spec/services/releaf/content/node/save_under_parent_spec.rb +49 -0
- data/spec/services/releaf/content/node/service_spec.rb +19 -0
- metadata +38 -21
- data/app/builders/releaf/content/go_to_dialog_builder.rb +0 -9
- data/app/views/releaf/content/nodes/go_to_dialog.ruby +0 -1
- data/lib/releaf/content/builders_autoload.rb +0 -18
- data/releaf-content.gemspec +0 -20
@@ -0,0 +1,90 @@
|
|
1
|
+
module Releaf
|
2
|
+
module Content::Node
|
3
|
+
class Copy
|
4
|
+
include Releaf::Content::Node::Service
|
5
|
+
attribute :parent_id, Integer, strict: false
|
6
|
+
|
7
|
+
def call
|
8
|
+
prevent_infinite_copy_loop
|
9
|
+
begin
|
10
|
+
new_node = nil
|
11
|
+
node.class.transaction do
|
12
|
+
new_node = make_copy
|
13
|
+
end
|
14
|
+
new_node
|
15
|
+
rescue ActiveRecord::RecordInvalid
|
16
|
+
add_error_and_raise 'descendant invalid'
|
17
|
+
else
|
18
|
+
node.update_settings_timestamp
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def prevent_infinite_copy_loop
|
23
|
+
return if node.self_and_descendants.find_by_id(parent_id).blank?
|
24
|
+
add_error_and_raise("source or descendant node can't be parent of new node")
|
25
|
+
end
|
26
|
+
|
27
|
+
def duplicate_under
|
28
|
+
new_node = nil
|
29
|
+
node.class.transaction do
|
30
|
+
new_node = node.class.new
|
31
|
+
new_node.assign_attributes_from(node)
|
32
|
+
new_node.content_id = duplicate_content.try(:id)
|
33
|
+
new_node.prevent_auto_update_settings_timestamp do
|
34
|
+
Releaf::Content::Node::SaveUnderParent.call(node: new_node, parent_id: parent_id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
new_node
|
38
|
+
end
|
39
|
+
|
40
|
+
def duplicate_content
|
41
|
+
return if node.content_id.blank?
|
42
|
+
|
43
|
+
new_content = node.content.class.new(cloned_content_attributes)
|
44
|
+
duplicate_content_dragonfly_attributes(new_content)
|
45
|
+
|
46
|
+
new_content.save!
|
47
|
+
new_content
|
48
|
+
end
|
49
|
+
|
50
|
+
def cloned_content_attributes
|
51
|
+
skippable_attribute_names = ["id"] + content_dragonfly_attributes
|
52
|
+
node.content.attributes.except(*skippable_attribute_names)
|
53
|
+
end
|
54
|
+
|
55
|
+
def duplicate_content_dragonfly_attributes(new_content)
|
56
|
+
content_dragonfly_attributes.each do |attribute_name|
|
57
|
+
accessor_name = attribute_name.gsub("_uid", "")
|
58
|
+
dragonfly_attachment = node.content.send(accessor_name)
|
59
|
+
|
60
|
+
if dragonfly_attachment.present?
|
61
|
+
begin
|
62
|
+
dragonfly_attachment.path # verify that the file exists
|
63
|
+
rescue Dragonfly::Job::Fetch::NotFound
|
64
|
+
dragonfly_attachment = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
new_content.send("#{attribute_name}=", nil)
|
69
|
+
new_content.send("#{accessor_name}=", dragonfly_attachment)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def content_dragonfly_attributes
|
74
|
+
node.content.class.attribute_names.select do |attribute_name|
|
75
|
+
Releaf::Builders::Utilities::ResolveAttributeFieldMethodName.new(object: node.content, attribute_name: attribute_name).file?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def make_copy
|
80
|
+
new_node = duplicate_under
|
81
|
+
|
82
|
+
node.children.each do |child|
|
83
|
+
self.class.new(node: child, parent_id: new_node.id).make_copy
|
84
|
+
end
|
85
|
+
|
86
|
+
new_node
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Releaf
|
2
|
+
module Content::Node
|
3
|
+
class Move
|
4
|
+
include Releaf::Content::Node::Service
|
5
|
+
attribute :parent_id, Integer, strict: false
|
6
|
+
|
7
|
+
def call
|
8
|
+
return if node.parent_id.to_i == parent_id
|
9
|
+
|
10
|
+
node.class.transaction do
|
11
|
+
Releaf::Content::Node::SaveUnderParent.call(node: node, parent_id: parent_id)
|
12
|
+
|
13
|
+
node.descendants.each do |descendant_node|
|
14
|
+
next if descendant_node.valid?
|
15
|
+
add_error_and_raise("descendant invalid")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Releaf
|
2
|
+
module Content::Node
|
3
|
+
class SaveUnderParent
|
4
|
+
include Releaf::Content::Node::Service
|
5
|
+
attribute :parent_id, Integer, strict: false
|
6
|
+
|
7
|
+
def call
|
8
|
+
node.parent_id = parent_id
|
9
|
+
if node.validate_root_locale_uniqueness?
|
10
|
+
# When copying root nodes it is important to reset locale to nil.
|
11
|
+
# Later user should fill in locale. This is needed to prevent
|
12
|
+
# Rails errors about conflicting routes.
|
13
|
+
node.locale = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
node.maintain_name
|
17
|
+
node.reasign_slug
|
18
|
+
node.save!
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Releaf
|
2
|
+
module Content::Node
|
3
|
+
module Service
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include Releaf::Service
|
6
|
+
|
7
|
+
included do
|
8
|
+
attribute :node, Releaf::Content::Node
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_error_and_raise(error)
|
12
|
+
node.errors.add(:base, error)
|
13
|
+
raise ActiveRecord::RecordInvalid.new(node)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,28 +1,5 @@
|
|
1
1
|
module Releaf
|
2
2
|
module Content::Node
|
3
|
-
# Validator to test if node is valid, when created under given parrent node
|
4
|
-
#
|
5
|
-
# validator needs :for and :under options, both can be either array of classes
|
6
|
-
# or single class.
|
7
|
-
#
|
8
|
-
# :for option specifies for which nodes validation should be applied
|
9
|
-
#
|
10
|
-
# :under option specifies under which nodes only single node of given type
|
11
|
-
# should be valid.
|
12
|
-
# If under is unspecified, then only single node with given class can be
|
13
|
-
# created under entrie content tree.
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
#
|
17
|
-
# class Node < ActiveRecord::Base
|
18
|
-
# includes Releaf::Content::Node
|
19
|
-
# validates_with Releaf::Content::Node::ParentValidator, for: [Text, Book], under: Store
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# In the example above, Text node or book node can be added in any leve
|
23
|
-
# under Store node, but only once.
|
24
|
-
# However they can be added to any other node as many times as needed, as
|
25
|
-
# long as none of ancestors are Store node.
|
26
3
|
class SinglenessValidator < ActiveModel::Validator
|
27
4
|
|
28
5
|
def validate node
|
@@ -67,7 +44,7 @@ module Releaf
|
|
67
44
|
# return some other parent, than @node.parent.ancestors, even though
|
68
45
|
# both return same node.
|
69
46
|
# Seams like a bug in AwesomeNestedSet (in case of @node.parent.ancestors).
|
70
|
-
parent_node =
|
47
|
+
parent_node = @node.class.find(@node.parent_id)
|
71
48
|
|
72
49
|
ancestor_node = parent_node.self_and_ancestors.where(content_type: ancestor_class_names).reorder(:depth).last
|
73
50
|
if ancestor_node.nil?
|
data/lib/releaf-content.rb
CHANGED
@@ -1,6 +1,85 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
require 'releaf/content/
|
6
|
-
require 'releaf/content/
|
1
|
+
require 'awesome_nested_set'
|
2
|
+
require 'stringex'
|
3
|
+
|
4
|
+
module Releaf::Content
|
5
|
+
require 'releaf/content/engine'
|
6
|
+
require 'releaf/content/configuration'
|
7
|
+
require 'releaf/content/router_proxy'
|
8
|
+
require 'releaf/content/node_mapper'
|
9
|
+
require 'releaf/content/acts_as_node'
|
10
|
+
require 'releaf/content/node'
|
11
|
+
require 'releaf/content/route'
|
12
|
+
|
13
|
+
# expose configuration wrapper methods as class methods for easier access
|
14
|
+
# so that, for example,
|
15
|
+
# Releaf::Content.models
|
16
|
+
# can be used instead of
|
17
|
+
# Releaf::Content.configuration.models
|
18
|
+
class << self
|
19
|
+
delegate :resources, :models, :default_model, :controllers, :routing, to: :configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.configuration
|
23
|
+
Releaf.application.config.content
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure_component
|
27
|
+
Releaf.application.config.add_configuration(
|
28
|
+
Releaf::Content::Configuration.new(
|
29
|
+
resources: { 'Node' => { controller: 'Releaf::Content::NodesController' } }
|
30
|
+
)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.initialize_component
|
35
|
+
Rails.application.config.middleware.use Releaf::Content::RoutesReloader
|
36
|
+
|
37
|
+
ActiveSupport.on_load :action_controller do
|
38
|
+
ActionDispatch::Routing::Mapper.send(:include, Releaf::Content::NodeMapper)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.draw_component_routes(router)
|
43
|
+
resources.each do |_model_name, options|
|
44
|
+
draw_resource_routes(router, options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.draw_resource_routes router, options
|
49
|
+
route_params = resource_route_params options
|
50
|
+
|
51
|
+
router.releaf_resources(*route_params) do
|
52
|
+
router.collection do
|
53
|
+
router.get :content_type_dialog
|
54
|
+
router.get :generate_url
|
55
|
+
end
|
56
|
+
|
57
|
+
router.member do
|
58
|
+
router.get :copy_dialog
|
59
|
+
router.post :copy
|
60
|
+
router.get :move_dialog
|
61
|
+
router.post :move
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.resource_route_params options
|
67
|
+
# Releaf::Content::NodesController -> releaf/content/nodes
|
68
|
+
controller_path = options[:controller].constantize.controller_path
|
69
|
+
controller_path_parts = controller_path.split('/')
|
70
|
+
|
71
|
+
resources_name = controller_path_parts.last
|
72
|
+
|
73
|
+
route_options = {
|
74
|
+
# releaf/content/nodes -> releaf/content
|
75
|
+
module: controller_path_parts.slice(0...-1).join('/'),
|
76
|
+
|
77
|
+
# releaf/content/nodes -> releaf_content_nodes
|
78
|
+
as: controller_path.gsub(/\//, '_'),
|
79
|
+
|
80
|
+
except: [:show]
|
81
|
+
}
|
82
|
+
|
83
|
+
[ resources_name, route_options ]
|
84
|
+
end
|
85
|
+
end
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
|
23
23
|
def acts_as_node_params
|
24
24
|
if acts_as_node_configuration[:params].nil?
|
25
|
-
Releaf::
|
25
|
+
Releaf::ResourceParams.new(self).values << :id
|
26
26
|
else
|
27
27
|
acts_as_node_configuration[:params] << :id
|
28
28
|
end
|
@@ -33,7 +33,7 @@ module ActiveRecord
|
|
33
33
|
# @return [Array] list of fields to display
|
34
34
|
def acts_as_node_fields
|
35
35
|
if acts_as_node_configuration[:fields].nil?
|
36
|
-
Releaf::
|
36
|
+
Releaf::ResourceFields.new(self).values
|
37
37
|
else
|
38
38
|
acts_as_node_configuration[:fields]
|
39
39
|
end
|
@@ -43,12 +43,6 @@ module ActiveRecord
|
|
43
43
|
# All the methods available to a record that has had <tt>acts_as_node</tt> specified.
|
44
44
|
module InstanceMethods
|
45
45
|
|
46
|
-
# Return object corresponding node object
|
47
|
-
# @return [::Node]
|
48
|
-
def node
|
49
|
-
::Node.find_by(content_type: self.class.name, content_id: id)
|
50
|
-
end
|
51
|
-
|
52
46
|
end
|
53
47
|
end
|
54
48
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Releaf::Content
|
2
|
+
class Configuration
|
3
|
+
include Virtus.model(strict: true)
|
4
|
+
attribute :resources, Hash
|
5
|
+
|
6
|
+
def resources=(value)
|
7
|
+
verify_resources_config(value)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def verify_resources_config(resource_config)
|
12
|
+
# perform some basic config structure validation
|
13
|
+
unless resource_config.is_a? Hash
|
14
|
+
raise Releaf::Error, "Releaf.application.config.content.resources must be a Hash"
|
15
|
+
end
|
16
|
+
|
17
|
+
resource_config.each do | key, values |
|
18
|
+
unless key.is_a? String
|
19
|
+
raise Releaf::Error, "Releaf.application.config.content.resources must have string keys"
|
20
|
+
end
|
21
|
+
unless values.is_a? Hash
|
22
|
+
raise Releaf::Error, "#{key} in Releaf.application.config.content.resources must have a hash value"
|
23
|
+
end
|
24
|
+
unless values[:controller].is_a? String
|
25
|
+
raise Releaf::Error, "#{key} in Releaf.application.config.content.resources must have controller class specified as a string"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def models
|
31
|
+
model_names.map(&:constantize)
|
32
|
+
end
|
33
|
+
|
34
|
+
def model_names
|
35
|
+
@model_names ||= resources.keys
|
36
|
+
end
|
37
|
+
|
38
|
+
def default_model
|
39
|
+
models.first
|
40
|
+
end
|
41
|
+
|
42
|
+
def controllers
|
43
|
+
controller_names.map(&:constantize)
|
44
|
+
end
|
45
|
+
|
46
|
+
def controller_names
|
47
|
+
@controller_names ||= resources.values.map { |options| options[:controller] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def routing
|
51
|
+
@routing ||= resources.map do | node_class_name, options |
|
52
|
+
routing = options[:routing] || {}
|
53
|
+
routing[:site] ||= nil
|
54
|
+
routing[:constraints] ||= nil
|
55
|
+
[ node_class_name, routing ]
|
56
|
+
end.to_h
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -1,40 +1,7 @@
|
|
1
|
-
require 'awesome_nested_set'
|
2
|
-
require 'stringex'
|
3
|
-
|
4
1
|
module Releaf::Content
|
5
|
-
require 'releaf/content/builders_autoload'
|
6
2
|
class Engine < ::Rails::Engine
|
7
3
|
initializer 'precompile', group: :all do |app|
|
8
|
-
app.config.assets.precompile += %w(
|
4
|
+
app.config.assets.precompile += %w(controllers/releaf/content/*)
|
9
5
|
end
|
10
6
|
end
|
11
|
-
|
12
|
-
def self.initialize_component
|
13
|
-
Rails.application.config.middleware.use Releaf::Content::RoutesReloader
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.draw_component_routes router
|
17
|
-
router.namespace :releaf, path: nil do
|
18
|
-
router.namespace :content, path: nil do
|
19
|
-
router.releaf_resources :nodes, except: [:show] do
|
20
|
-
router.collection do
|
21
|
-
router.get :content_type_dialog
|
22
|
-
router.get :generate_url
|
23
|
-
router.get :go_to_dialog
|
24
|
-
end
|
25
|
-
|
26
|
-
router.member do
|
27
|
-
router.get :copy_dialog
|
28
|
-
router.post :copy
|
29
|
-
router.get :move_dialog
|
30
|
-
router.post :move
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
ActiveSupport.on_load :action_controller do
|
38
|
-
ActionDispatch::Routing::Mapper.send(:include, Releaf::Content::NodeMapper)
|
39
|
-
end
|
40
7
|
end
|
data/lib/releaf/content/node.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Releaf::Content
|
2
2
|
module Node
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
# TODO Node should be configurable
|
5
4
|
|
6
5
|
def locale_selection_enabled?
|
7
6
|
false
|
8
7
|
end
|
9
8
|
|
10
|
-
def build_content(params = {}
|
9
|
+
def build_content(params = {})
|
11
10
|
self.content = content_class.new(params)
|
12
11
|
end
|
13
12
|
|
@@ -17,11 +16,18 @@ module Releaf::Content
|
|
17
16
|
|
18
17
|
# Return node public path
|
19
18
|
def path
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
"/" + path_parts.join("/") + (trailing_slash_for_path? ? "/" : "")
|
20
|
+
end
|
21
|
+
|
22
|
+
def path_parts
|
23
|
+
list = []
|
24
|
+
list += parent.path_parts if parent
|
25
|
+
list << slug.to_s
|
26
|
+
list
|
27
|
+
end
|
28
|
+
|
29
|
+
def trailing_slash_for_path?
|
30
|
+
Rails.application.routes.default_url_options[:trailing_slash] == true
|
25
31
|
end
|
26
32
|
|
27
33
|
def to_s
|
@@ -45,40 +51,21 @@ module Releaf::Content
|
|
45
51
|
end
|
46
52
|
|
47
53
|
def attributes_to_not_copy
|
48
|
-
%w[content_id depth id item_position lft rgt slug created_at updated_at]
|
54
|
+
list = %w[content_id depth id item_position lft rgt slug created_at updated_at]
|
55
|
+
list << "locale" if locale_before_type_cast.blank?
|
56
|
+
list
|
49
57
|
end
|
50
58
|
|
51
59
|
def attributes_to_copy
|
52
60
|
self.class.column_names - attributes_to_not_copy
|
53
61
|
end
|
54
62
|
|
55
|
-
def copy
|
56
|
-
|
57
|
-
begin
|
58
|
-
new_node = nil
|
59
|
-
self.class.transaction do
|
60
|
-
new_node = _copy!(parent_id)
|
61
|
-
end
|
62
|
-
new_node
|
63
|
-
rescue ActiveRecord::RecordInvalid
|
64
|
-
add_error_and_raise 'descendant invalid'
|
65
|
-
else
|
66
|
-
update_settings_timestamp
|
67
|
-
end
|
63
|
+
def copy(parent_id)
|
64
|
+
Releaf::Content::Node::Copy.call(node: self, parent_id: parent_id)
|
68
65
|
end
|
69
66
|
|
70
|
-
def move
|
71
|
-
|
72
|
-
|
73
|
-
self.class.transaction do
|
74
|
-
save_under(parent_id)
|
75
|
-
descendants.each do |node|
|
76
|
-
next if node.valid?
|
77
|
-
add_error_and_raise 'descendant invalid'
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
self
|
67
|
+
def move(parent_id)
|
68
|
+
Releaf::Content::Node::Move.call(node: self, parent_id: parent_id)
|
82
69
|
end
|
83
70
|
|
84
71
|
# Maintain unique name within parent_id scope.
|
@@ -118,59 +105,18 @@ module Releaf::Content
|
|
118
105
|
self_and_ancestors.where(active: false).any? == false
|
119
106
|
end
|
120
107
|
|
121
|
-
def add_error_and_raise error
|
122
|
-
errors.add(:base, error)
|
123
|
-
raise ActiveRecord::RecordInvalid.new(self)
|
124
|
-
end
|
125
|
-
|
126
|
-
def duplicate_content
|
127
|
-
return nil if content_id.blank?
|
128
|
-
|
129
|
-
new_content = content.dup
|
130
|
-
new_content.save!
|
131
|
-
new_content
|
132
|
-
end
|
133
|
-
|
134
|
-
def copy_attributes_from node
|
135
|
-
node.attributes_to_copy.each do |attribute|
|
136
|
-
send("#{attribute}=", node.send(attribute))
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def duplicate_under! parent_id
|
141
|
-
new_node = nil
|
142
|
-
self.class.transaction do
|
143
|
-
new_node = self.class.new
|
144
|
-
new_node.copy_attributes_from self
|
145
|
-
new_node.content_id = duplicate_content.try(:id)
|
146
|
-
new_node.prevent_auto_update_settings_timestamp do
|
147
|
-
new_node.save_under(parent_id)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
new_node
|
151
|
-
end
|
152
|
-
|
153
108
|
def reasign_slug
|
154
109
|
self.slug = nil
|
155
110
|
ensure_unique_url
|
156
111
|
end
|
157
112
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
161
|
-
# When copying root nodes it is important to reset locale to nil.
|
162
|
-
# Later user should fill in locale. This is needed to prevent
|
163
|
-
# Rails errors about conflicting routes.
|
164
|
-
self.locale = nil
|
113
|
+
def assign_attributes_from(source_node)
|
114
|
+
source_node.attributes_to_copy.each do |attribute|
|
115
|
+
send("#{attribute}=", source_node.send(attribute))
|
165
116
|
end
|
166
|
-
|
167
|
-
self.item_position = self.class.children_max_item_position(self.parent) + 1
|
168
|
-
maintain_name
|
169
|
-
reasign_slug
|
170
|
-
save!
|
171
117
|
end
|
172
118
|
|
173
|
-
def prevent_auto_update_settings_timestamp
|
119
|
+
def prevent_auto_update_settings_timestamp
|
174
120
|
original = @prevent_auto_update_settings_timestamp
|
175
121
|
@prevent_auto_update_settings_timestamp = true
|
176
122
|
yield
|
@@ -178,12 +124,16 @@ module Releaf::Content
|
|
178
124
|
@prevent_auto_update_settings_timestamp = original
|
179
125
|
end
|
180
126
|
|
181
|
-
|
127
|
+
def update_settings_timestamp
|
128
|
+
self.class.updated
|
129
|
+
end
|
182
130
|
|
183
131
|
def validate_root_locale_uniqueness?
|
184
132
|
locale_selection_enabled? && root?
|
185
133
|
end
|
186
134
|
|
135
|
+
protected
|
136
|
+
|
187
137
|
def validate_parent_node_is_not_self
|
188
138
|
return if parent_id.nil?
|
189
139
|
return if parent_id.to_i != id
|
@@ -198,28 +148,10 @@ module Releaf::Content
|
|
198
148
|
|
199
149
|
private
|
200
150
|
|
201
|
-
def _copy! parent_id
|
202
|
-
new_node = duplicate_under! parent_id
|
203
|
-
|
204
|
-
children.each do |child|
|
205
|
-
child.send(:_copy!, new_node.id)
|
206
|
-
end
|
207
|
-
new_node
|
208
|
-
end
|
209
|
-
|
210
|
-
def prevent_infinite_copy_loop(parent_id)
|
211
|
-
return if self_and_descendants.find_by_id(parent_id).blank?
|
212
|
-
add_error_and_raise("source or descendant node can't be parent of new node")
|
213
|
-
end
|
214
|
-
|
215
151
|
def prevent_auto_update_settings_timestamp?
|
216
152
|
@prevent_auto_update_settings_timestamp == true
|
217
153
|
end
|
218
154
|
|
219
|
-
def update_settings_timestamp
|
220
|
-
self.class.updated
|
221
|
-
end
|
222
|
-
|
223
155
|
module ClassMethods
|
224
156
|
def updated_at
|
225
157
|
Releaf::Settings['releaf.content.nodes.updated_at']
|
@@ -254,7 +186,7 @@ module Releaf::Content
|
|
254
186
|
|
255
187
|
included do
|
256
188
|
acts_as_nested_set order_column: :item_position
|
257
|
-
acts_as_list scope: :parent_id, column: :item_position
|
189
|
+
acts_as_list scope: :parent_id, column: :item_position, add_new_at: :bottom
|
258
190
|
|
259
191
|
default_scope { order(:item_position) }
|
260
192
|
scope :active, ->() { where(active: true) }
|
@@ -266,9 +198,6 @@ module Releaf::Content
|
|
266
198
|
validates_presence_of :parent, if: :parent_id?
|
267
199
|
validate :validate_parent_node_is_not_self
|
268
200
|
validate :validate_parent_is_not_descendant
|
269
|
-
|
270
|
-
alias_attribute :to_text, :name
|
271
|
-
|
272
201
|
belongs_to :content, polymorphic: true, dependent: :destroy
|
273
202
|
accepts_nested_attributes_for :content
|
274
203
|
|