nocms-blocks 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/README.md +7 -3
- data/app/models/no_cms/blocks/block.rb +31 -128
- data/app/models/no_cms/blocks/concerns/serializing_fields.rb +386 -0
- data/app/models/no_cms/blocks/layout.rb +98 -0
- data/app/views/no_cms/blocks/blocks/_default.html.erb +6 -0
- data/db/migrate/20150709132202_add_non_translated_fields_info_to_no_cms_blocks_block.rb +5 -0
- data/db/migrate/20150710112549_move_layout_from_no_cms_blocks_block_translations_to_no_cms_blocks_blocks.rb +19 -0
- data/lib/generators/nocms/templates/config/initializers/nocms/blocks.rb +8 -0
- data/lib/no_cms/blocks/version.rb +1 -1
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +3 -2
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +163 -0
- data/spec/dummy/log/test.log +94024 -0
- data/spec/dummy/public/uploads/test_image/logo/2/logo.png +0 -0
- data/spec/dummy/public/uploads/test_image/logo/2/logo2.png +0 -0
- data/spec/dummy/public/uploads/test_image/logo/3/logo.png +0 -0
- data/spec/dummy/public/uploads/test_image/logo/4/logo.png +0 -0
- data/spec/dummy/public/uploads/test_image/logo/5/logo.png +0 -0
- data/spec/dummy/public/uploads/test_image/logo/6/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-1395/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-1590/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-1891/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-1891/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-2425/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-3650/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-3867/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-3867/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-5629/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-5795/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-5882/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194769-17662-9375/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-0450/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-0733/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-0733/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-1087/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-1087/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-1788/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-2101/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-4443/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-5065/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-6456/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-8131/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194790-17727-9096/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194856-17785-0815/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194856-17785-4789/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194856-17785-7685/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-0259/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-0349/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-0476/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-1997/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-3813/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-3813/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-4455/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-5316/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-5316/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-7121/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-7447/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-7677/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-8037/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194857-17785-8791/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194878-17844-1352/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194878-17844-1557/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194878-17844-5177/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194878-17844-5338/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194878-17844-8747/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-3191/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-3986/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-5951/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-6104/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-7114/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-7114/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-7617/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-8185/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-8495/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-8495/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-8991/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194879-17844-9466/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194892-17862-1771/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436194926-17904-9747/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195033-17981-2265/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195045-18015-3603/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195085-18055-8412/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195101-18097-0044/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195126-18165-6939/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195152-18225-1850/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195169-18262-2283/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195186-18300-3395/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195205-18336-0453/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195242-18389-3554/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195255-18420-9336/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195745-18605-6163/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195823-18669-7443/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195886-18739-5334/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195900-18776-9749/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436195935-18824-1992/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196060-18894-4158/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196106-18943-1035/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196156-18987-1445/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196187-19045-9003/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196275-19125-3257/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436196321-19169-5591/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-0160/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-0565/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-1519/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-2202/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-2400/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-2928/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-3260/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-4333/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-5122/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-6333/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-6333/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-7928/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-9359/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-9392/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-9549/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-9549/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258374-8961-9648/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258382-8967-0797/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258453-9165-7375/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258549-9282-2039/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258623-9355-6670/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436258674-9394-2929/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436264869-10860-2169/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276653-16968-2375/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276734-17282-9777/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276770-17431-4333/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276781-17463-5971/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276875-17556-1972/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276882-17588-9186/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436276896-17657-9942/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436277157-17795-9344/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436277178-17833-8883/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436277781-18431-2830/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436278571-18860-1079/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436282613-22892-0135/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436282638-22953-7833/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436282887-23026-0068/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436282978-23160-8886/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-1740/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-3170/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-3501/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-6393/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-6862/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-7741/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-8051/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-8064/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-8093/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436284256-24634-9497/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-0200/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-0325/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-1380/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-4150/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-4347/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-5072/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-5891/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-6304/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-6620/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-6703/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-8254/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436553862-9485-8313/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-0021/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-1865/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-2510/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-3771/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-4441/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-5712/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-6456/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-6520/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-8183/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-8675/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-8953/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554155-9646-9271/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554181-9685-7099/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554233-9708-0769/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554254-9739-7026/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554350-9834-3927/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554416-9875-0666/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554519-9921-2596/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554569-9980-0004/logo.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554694-10292-1775/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554694-10292-5549/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554722-10308-2875/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554732-10340-8854/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436554994-10463-9859/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436555134-10554-3506/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436555227-10604-7612/logo2.png +0 -0
- data/spec/dummy/public/uploads/tmp/1436555450-10700-1633/logo2.png +0 -0
- data/spec/models/no_cms/blocks/duplicating_blocks_spec.rb +161 -0
- data/spec/models/no_cms/blocks/i18n_blocks_spec.rb +101 -0
- data/spec/models/no_cms/blocks/layout_spec.rb +125 -0
- data/spec/spec_helper.rb +3 -0
- metadata +385 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbc9eae202e6ec4df5bdba9d91c4a842e03e2f3d
|
4
|
+
data.tar.gz: 2523df1872e26d06a714b3bc9c8552c49c07c279
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 841a55342e8a5b30e2a4c4a5c2771d9d231a4ce68fbe483896159823d44332130fc2b09b8ba214927cb395858301565bac8ef03a98e34c9df8e1ca67b7911ec3
|
7
|
+
data.tar.gz: cefb0459db81a0af3dd4e10f3da524b6c6d5359a0aecfe5b1b6cd5664d30c1d09315bc0a5615dab8ad2cea01f16cc5ffd5a3f0b2bc9a0c36c37b883529e0c1fe
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
1.1.0
|
2
|
+
|
3
|
+
- I18n behaviour fixed
|
4
|
+
* Separated objects cache for translations
|
5
|
+
* fields info both in the block and the translation
|
6
|
+
|
7
|
+
- Globalize dependency correctly specified in the gemspec
|
8
|
+
|
9
|
+
- Latest versions of awesome-nested-set (3.0.2) and globalize (5.0.1)
|
10
|
+
|
1
11
|
1.0.0
|
2
12
|
|
3
13
|
- First released version.
|
data/README.md
CHANGED
@@ -6,15 +6,19 @@ This is a Rails engine with a basic functionality of customizable blocks of cont
|
|
6
6
|
|
7
7
|
## How do I install it?
|
8
8
|
|
9
|
-
|
9
|
+
Just include in your Gemfile:
|
10
10
|
|
11
|
-
|
11
|
+
```ruby
|
12
|
+
gem "nocms-blocks"
|
13
|
+
```
|
14
|
+
|
15
|
+
If you're brave and want to use the last development version you can use:
|
12
16
|
|
13
17
|
```ruby
|
14
18
|
gem "nocms-blocks", git: 'git@github.com:simplelogica/nocms-blocks.git'
|
15
19
|
```
|
16
20
|
|
17
|
-
|
21
|
+
Once the gem is installed you can import all the migrations:
|
18
22
|
|
19
23
|
```
|
20
24
|
rake no_cms_blocks:install:migrations
|
@@ -9,152 +9,55 @@ module NoCms::Blocks
|
|
9
9
|
scope :no_drafts, ->() { where_with_locale(draft: false) }
|
10
10
|
scope :roots, ->() { where parent_id: nil }
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
attr_reader :cached_objects
|
12
|
+
translates :draft
|
13
|
+
include NoCms::Blocks::Concerns::SerializingFields
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
serialize :fields_info, Hash
|
15
|
+
##
|
16
|
+
# In the block we get all the fields so it can accept all of them
|
17
|
+
def fields_configuration
|
18
|
+
layout_config.fields
|
21
19
|
end
|
22
20
|
|
23
|
-
after_initialize :set_blank_fields
|
24
|
-
before_save :save_related_objects
|
25
|
-
|
26
|
-
validates :fields_info, presence: { allow_blank: true }
|
27
21
|
validates :layout, presence: true
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def layout_config
|
35
|
-
NoCms::Blocks.block_layouts.stringify_keys[layout]
|
36
|
-
end
|
23
|
+
##
|
24
|
+
# A block dups all it's children and the translations
|
25
|
+
def duplicate_self new_self
|
37
26
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
def has_field? field
|
43
|
-
# We have the field if...
|
44
|
-
!layout_config.nil? && # We have a layout configuration AND
|
45
|
-
(
|
46
|
-
!layout_config[:fields].symbolize_keys[field.to_sym].nil? || # We have this field OR
|
47
|
-
!layout_config[:fields].symbolize_keys[field.to_s.gsub(/\_id$/, '').to_sym].nil? # we remove the final _id and then we have the field
|
48
|
-
)
|
49
|
-
end
|
50
|
-
|
51
|
-
def field_type field
|
52
|
-
return nil unless has_field?(field)
|
53
|
-
layout_config[:fields].symbolize_keys[field.to_sym]
|
54
|
-
end
|
55
|
-
|
56
|
-
def read_field field
|
57
|
-
return nil unless has_field?(field)
|
58
|
-
|
59
|
-
value = fields_info[field.to_sym] || # first, we get the value
|
60
|
-
@cached_objects[field.to_sym] # or we get it from the cached objects
|
61
|
-
|
62
|
-
# If value is still nil, but the field exists we must get the object from the database
|
63
|
-
if value.nil?
|
64
|
-
field_type = field_type(field)
|
65
|
-
field_id = fields_info["#{field}_id".to_sym]
|
66
|
-
value = @cached_objects[field.to_sym] = field_type.find(field_id) unless field_id.nil?
|
67
|
-
end
|
27
|
+
new_self.translations = translations.map(&:dup)
|
28
|
+
new_self.translations.each { |t| t.globalized_model = new_self }
|
68
29
|
|
69
|
-
|
70
|
-
|
71
|
-
value = @cached_objects[field.to_sym] = field_type.new
|
30
|
+
children.each do |child|
|
31
|
+
new_self.children << child.dup
|
72
32
|
end
|
73
|
-
value
|
74
33
|
end
|
75
34
|
|
76
|
-
|
77
|
-
return nil unless has_field?(field)
|
78
|
-
field_type = field_type field
|
79
|
-
# If field type is a model then we update the cached object
|
80
|
-
if field_type.is_a?(Class) && field_type < ActiveRecord::Base
|
81
|
-
# First, we initialize the object if we don't read the object (it loads it into the cached objects)
|
82
|
-
@cached_objects[field.to_sym] = field_type.new if read_field(field).nil?
|
83
|
-
# Then, assign attributes
|
84
|
-
@cached_objects[field.to_sym].assign_attributes value
|
85
|
-
else # If it's a model then a new object or update the previous one
|
86
|
-
self.fields_info = fields_info.merge field.to_sym => value # when updating through an object (i.e. the page updates through nested attributes) fields_info[field.to_sym] = value doesn't work. Kudos to Rubo for this fix
|
87
|
-
end
|
88
|
-
end
|
35
|
+
class Translation
|
89
36
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
field = m.to_s
|
95
|
-
write_accessor = field.ends_with? '='
|
96
|
-
field.gsub!(/\=$/, '')
|
97
|
-
|
98
|
-
# If this field actually exists, then we write it or read it.
|
99
|
-
if has_field?(field)
|
100
|
-
write_accessor ?
|
101
|
-
write_field(field, args.first) :
|
102
|
-
read_field(field.to_sym)
|
103
|
-
else
|
104
|
-
super
|
37
|
+
##
|
38
|
+
# In the translation we get only the translated fields
|
39
|
+
def fields_configuration
|
40
|
+
layout_config.translated_fields
|
105
41
|
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# When we are assigning attributes (this method is called in new, create...)
|
109
|
-
# we must split those fields from our current layout and those who are not
|
110
|
-
# (they must be attributes).
|
111
|
-
# Attributes are processed the usual way and fields are written later
|
112
|
-
def assign_attributes new_attributes
|
113
|
-
fields = []
|
114
|
-
|
115
|
-
set_blank_fields
|
116
|
-
|
117
|
-
# We get the layout
|
118
|
-
new_layout = new_attributes[:layout] || new_attributes['layout']
|
119
|
-
self.layout = new_layout unless new_layout.nil?
|
120
|
-
|
121
|
-
Rails.logger.info "Searching #{new_attributes.keys.inspect} fields in #{self.layout} layout"
|
122
|
-
|
123
|
-
# And now separate fields and attributes
|
124
|
-
fields = new_attributes.select{|k, _| has_field? k }.symbolize_keys
|
125
|
-
new_attributes.reject!{|k, _| has_field? k }
|
126
42
|
|
127
|
-
|
43
|
+
##
|
44
|
+
# Sometimes the translation still won't have the globalized_model linked
|
45
|
+
# (e.g. before it's saved for the first time) and we must have a mechanism
|
46
|
+
# to be able to store a temporary layout
|
47
|
+
attr_accessor :layout
|
128
48
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
49
|
+
##
|
50
|
+
# If we don't have a globalized model yet we return our temporary layout
|
51
|
+
def layout
|
52
|
+
globalized_model.nil? ? @layout : globalized_model.layout
|
133
53
|
end
|
134
|
-
end
|
135
54
|
|
136
|
-
|
137
|
-
@cached_objects = {}
|
138
|
-
super
|
55
|
+
include NoCms::Blocks::Concerns::SerializingFields
|
139
56
|
end
|
140
57
|
|
141
|
-
|
142
|
-
|
143
|
-
def set_blank_fields
|
144
|
-
self.fields_info ||= {}
|
145
|
-
@cached_objects ||= {}
|
146
|
-
end
|
58
|
+
accepts_nested_attributes_for :children, allow_destroy: true
|
59
|
+
accepts_nested_attributes_for :translations
|
147
60
|
|
148
|
-
def save_related_objects
|
149
|
-
# Now we save each activerecord related object
|
150
|
-
cached_objects.each do |field, object|
|
151
|
-
# Notice that we don't care if the object is actually saved
|
152
|
-
# We don't care because there may be some cases where no real information is sent to an object but something is sent (i.e. the locale in a new Globalize translation) and then the object is created empty
|
153
|
-
# When this happens if we save! the object an error is thrown and we can't leave the object blank
|
154
|
-
if object.is_a?(ActiveRecord::Base) && object.save
|
155
|
-
fields_info["#{field}_id".to_sym] = object.id
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
61
|
end
|
62
|
+
|
160
63
|
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
module NoCms
|
2
|
+
module Blocks
|
3
|
+
module Concerns
|
4
|
+
module SerializingFields
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
self.included do
|
8
|
+
|
9
|
+
serialize :fields_info, Hash
|
10
|
+
|
11
|
+
after_initialize :set_blank_fields
|
12
|
+
|
13
|
+
before_save :save_related_objects
|
14
|
+
|
15
|
+
validates :fields_info, presence: { allow_blank: true }
|
16
|
+
|
17
|
+
##
|
18
|
+
# This attribute stores all the objects referenced on those fields
|
19
|
+
# from an AR subtype.
|
20
|
+
#
|
21
|
+
# It acts both as a cache and as a way to edit or create AR objects
|
22
|
+
# and save them when the block is saved.
|
23
|
+
attr_reader :cached_objects
|
24
|
+
|
25
|
+
|
26
|
+
##
|
27
|
+
# This method checks wether the block's layout has cache configured
|
28
|
+
# and returns it.
|
29
|
+
#
|
30
|
+
# If it hasn't it returns the global cache_enabled configuration for
|
31
|
+
# NoCms::Blocks
|
32
|
+
def cache_enabled?
|
33
|
+
layout_config.cache_enabled?
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Old version without '?' mantained for historical reasons
|
38
|
+
alias_method :cache_enabled, :cache_enabled?
|
39
|
+
|
40
|
+
##
|
41
|
+
# Returns a hash with the layout information read from the blocks
|
42
|
+
# initializer and the 'layout' field on the corresponding object.
|
43
|
+
def layout_config
|
44
|
+
return if layout.nil?
|
45
|
+
@layout_config ||= NoCms::Blocks::Layout.find layout
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Returns the template read from the layout configuration
|
50
|
+
def template
|
51
|
+
layout_config.template if layout_config
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# This method checks that we have the field passed as parameter in our
|
56
|
+
# layout configuration.
|
57
|
+
#
|
58
|
+
# It also takes into account the case where we have an AR object and
|
59
|
+
# we're asking just for its id.
|
60
|
+
def has_field? field
|
61
|
+
# We have the field if...
|
62
|
+
!layout_config.nil? && # We have a layout configuration AND
|
63
|
+
!layout_config.field(field).nil? # We have this field
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# This method tells wether we are in a translation and we must manage
|
68
|
+
# translated fields or not
|
69
|
+
def is_translation?
|
70
|
+
!self.respond_to?(:translations)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Returns the type of a field in the current layout configuration of
|
75
|
+
# this block.
|
76
|
+
#
|
77
|
+
# If the field is not present in the layout configuration it returns
|
78
|
+
# nil.
|
79
|
+
def field_type field
|
80
|
+
return nil unless has_field?(field)
|
81
|
+
fields_configuration.symbolize_keys[field.to_sym][:type]
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Returns the stored value of the field for this block.
|
86
|
+
#
|
87
|
+
# If the field is not present in the layout configuration it returns
|
88
|
+
# nil.
|
89
|
+
#
|
90
|
+
# If the field is an Active Record object but it's not present on our
|
91
|
+
# objects cache we fetch it from the database using the id stored in
|
92
|
+
# the #{field}_id field.
|
93
|
+
#
|
94
|
+
# If it's an Active Record object but we don't have the #{field}_id
|
95
|
+
# field then it creates (with new, not with create) a new one and
|
96
|
+
# stores it in the objects cache. Later, if the block is saved, this
|
97
|
+
# object will be saved too.
|
98
|
+
def read_field field
|
99
|
+
raise NoMethodError.new("field #{field} is not defined in the block layout") unless has_field?(field)
|
100
|
+
|
101
|
+
# first, we get the value
|
102
|
+
value = fields_info[field.to_sym] ||
|
103
|
+
# or we get it from the cached objects
|
104
|
+
@cached_objects[field.to_sym]
|
105
|
+
|
106
|
+
# If value is still nil, but the field exists we must get the object
|
107
|
+
# from the database
|
108
|
+
if value.nil?
|
109
|
+
field_type = field_type(field)
|
110
|
+
field_id = fields_info["#{field}_id".to_sym]
|
111
|
+
unless field_id.nil?
|
112
|
+
value = field_type.find(field_id)
|
113
|
+
@cached_objects[field.to_sym] = value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# If value is still nil, and the field_type is an ActiveRecord
|
118
|
+
# class, then we build a new one
|
119
|
+
if value.nil? && field_type.is_a?(Class)
|
120
|
+
value = field_type.new
|
121
|
+
@cached_objects[field.to_sym] = value
|
122
|
+
end
|
123
|
+
value
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# This method stores the parameter value into the corresponding field.
|
128
|
+
#
|
129
|
+
# If the field is an Active Record object then we load it into the
|
130
|
+
# objects cache and assign it the value through an assign_attributes.
|
131
|
+
# This solves the scenario of a nested form where a hash is passed as
|
132
|
+
# the value of the field.
|
133
|
+
def write_field field, value
|
134
|
+
raise NoMethodError.new("field #{field} is not defined in the block layout") unless has_field?(field)
|
135
|
+
field_type = field_type field
|
136
|
+
# If field type is a model then we update the cached object
|
137
|
+
if field_type.is_a?(Class) && field_type < ActiveRecord::Base
|
138
|
+
|
139
|
+
# We read the object and assign it the attributes attributes.
|
140
|
+
# Since we use the read_field method it will take into account
|
141
|
+
# if the AR object needs to be build
|
142
|
+
read_field(field).assign_attributes value
|
143
|
+
|
144
|
+
# Even if the fields_info has not changed we need to store the
|
145
|
+
# modification, so an association may be saved in cascade (e.g.
|
146
|
+
# the translation of a block would not be saved if we don't force
|
147
|
+
# this)
|
148
|
+
fields_info_will_change!
|
149
|
+
else
|
150
|
+
# If it's not a model then we merge with the previous value
|
151
|
+
|
152
|
+
# when updating through an object (i.e. the page updates through
|
153
|
+
# nested attributes) fields_info[field.to_sym] = value doesn't
|
154
|
+
# work. Kudos to Rubo for this fix
|
155
|
+
self.fields_info = fields_info.nil? ?
|
156
|
+
{ field.to_sym => value } :
|
157
|
+
fields_info.merge(field.to_sym => value)
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# This method duplicates a field and stores its value.
|
164
|
+
#
|
165
|
+
# It takes into account that the field may be an AR object and updates
|
166
|
+
# the cached objects.
|
167
|
+
#
|
168
|
+
# We have different options of duplication depending on the field's
|
169
|
+
# configuration:
|
170
|
+
#
|
171
|
+
# * duplication: It's the default behaviour. It just performs a dup
|
172
|
+
# of the field and expects the attached object to implement dup in
|
173
|
+
# a proper way.
|
174
|
+
#
|
175
|
+
# * nullify: It doesn't dup the field, it empties it. It's useful for
|
176
|
+
# objects we don't want to duplicate, like images in S3 (it can
|
177
|
+
# raise a timeout exception when duplicating).
|
178
|
+
#
|
179
|
+
# * link: It doesn't dup the field but stores the same object. It's
|
180
|
+
# useful in Active Record fields so we can store the same id and
|
181
|
+
# not creating a duplicate of the object (e.g. if we have a block
|
182
|
+
# with a related post we don't want the post to be duplicated)
|
183
|
+
def duplicate_field field
|
184
|
+
field_type = field_type field
|
185
|
+
field_value = read_field(field)
|
186
|
+
|
187
|
+
dupped_value = case layout_config.field(field)[:duplicate]
|
188
|
+
# When dupping we just dp the object and expect it has the right
|
189
|
+
# behaviour. If it's nil we save nil (you can't dup NilClass)
|
190
|
+
when :dup
|
191
|
+
field_value.nil? ? nil : field_value.dup
|
192
|
+
# When nullifying we return nil
|
193
|
+
when :nullify
|
194
|
+
nil
|
195
|
+
when :link
|
196
|
+
field_value
|
197
|
+
end
|
198
|
+
|
199
|
+
if field_type.is_a?(Class) && field_type < ActiveRecord::Base
|
200
|
+
# We save in the objects cache the dupped object
|
201
|
+
@cached_objects[field.to_sym] = dupped_value
|
202
|
+
# and then we store the new id in the fields_info hash
|
203
|
+
fields_info["#{field}_id".to_sym] =
|
204
|
+
dupped_value.nil? ? nil : dupped_value.id
|
205
|
+
else
|
206
|
+
# else we just dup it and save it into fields_info.
|
207
|
+
fields_info[field.to_sym] = dupped_value
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Saves every related object from the objects cache
|
213
|
+
def save_related_objects
|
214
|
+
# Now we save each activerecord related object
|
215
|
+
@cached_objects.each do |field, object|
|
216
|
+
# Notice that we don't care if the object is actually saved.
|
217
|
+
#
|
218
|
+
# We don't care because there may be some cases where no real
|
219
|
+
# information is sent to an object but something is sent (i.e. the
|
220
|
+
# locale in a new Globalize translation) and then the object is
|
221
|
+
# created empty.
|
222
|
+
#
|
223
|
+
# When this happens if we save! the object an error is thrown and
|
224
|
+
# we can't leave the object blank
|
225
|
+
if object.is_a?(ActiveRecord::Base) && object.save
|
226
|
+
fields_info["#{field}_id".to_sym] = object.id
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
##
|
232
|
+
# In this missing method we check wether we're asking for one field
|
233
|
+
# in which case we will read or write it.
|
234
|
+
#
|
235
|
+
# If there's no field we just let it go to super.
|
236
|
+
def method_missing(m, *args, &block)
|
237
|
+
# We get the name of the field stripping out the '=' for writers
|
238
|
+
field = m.to_s
|
239
|
+
write_accessor = field.ends_with? '='
|
240
|
+
field.gsub!(/\=$/, '')
|
241
|
+
|
242
|
+
|
243
|
+
# If we don't have this field then we send it to super and pry
|
244
|
+
if field == 'layout' || !has_field?(field)
|
245
|
+
super
|
246
|
+
# If this field exists, and it's not translated, then we do whatever
|
247
|
+
# we need to do
|
248
|
+
elsif !layout_config.field(field)[:translated]
|
249
|
+
write_accessor ?
|
250
|
+
write_field(field, args.first) :
|
251
|
+
read_field(field.to_sym)
|
252
|
+
|
253
|
+
# If it's translated but we are not in the translation (we check
|
254
|
+
# this by checking if we have translations) then we use the
|
255
|
+
# default translation to obtain it
|
256
|
+
elsif !self.is_translation? &&
|
257
|
+
layout_config.field(field)[:translated]
|
258
|
+
|
259
|
+
# When we are creating the block we still have no translation
|
260
|
+
# and we need to fill the layout. Otherwise no write or read
|
261
|
+
# field will work
|
262
|
+
translation.layout = self.layout
|
263
|
+
|
264
|
+
write_accessor ?
|
265
|
+
translation.write_field(field, args.first) :
|
266
|
+
translation.read_field(field.to_sym)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
##
|
271
|
+
# When we are assigning attributes (this method is called in new,
|
272
|
+
# create...) we must split those fields from our current layout and
|
273
|
+
# those who are not (they must be attributes).
|
274
|
+
#
|
275
|
+
# Attributes are processed the usual way and fields are written later
|
276
|
+
def assign_attributes new_attributes
|
277
|
+
fields = []
|
278
|
+
|
279
|
+
set_blank_fields
|
280
|
+
|
281
|
+
# We get the layout
|
282
|
+
new_layout = new_attributes[:layout] || new_attributes['layout']
|
283
|
+
self.layout = new_layout unless new_layout.nil?
|
284
|
+
|
285
|
+
Rails.logger.info "Searching #{new_attributes.keys.inspect} fields"+
|
286
|
+
"in #{self.layout} layout"
|
287
|
+
|
288
|
+
# And now separate fields and attributes
|
289
|
+
fields = new_attributes.select{|k, _| has_field? k }.symbolize_keys
|
290
|
+
# Now we filter those fields we must not manage because we are (or
|
291
|
+
# not) in a translation. I.e: if we have a translated field, but we
|
292
|
+
# are not in a translation then we let the translated field go and
|
293
|
+
# not manage it here
|
294
|
+
fields.select!{|k, _| layout_config.field(k)[:translated] == is_translation? }
|
295
|
+
|
296
|
+
# We purge the fields from the attributes
|
297
|
+
new_attributes.reject!{|k, _| fields.has_key? k }
|
298
|
+
|
299
|
+
# If we have translations we're going to need the layout in their
|
300
|
+
# attributes too so they can validate the fields.
|
301
|
+
# This is actually only neccesary when creating the translations,
|
302
|
+
# but we can afford to send the layout always to the translations
|
303
|
+
if new_attributes.has_key? :translations_attributes
|
304
|
+
new_attributes[:translations_attributes].each do |translation|
|
305
|
+
translation[:layout] = self.layout
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
super(new_attributes)
|
310
|
+
|
311
|
+
Rails.logger.info "Writing #{fields.inspect} to #{self.layout} block"
|
312
|
+
|
313
|
+
fields.each do |field_name, value|
|
314
|
+
self.write_field field_name, value
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
##
|
319
|
+
# It cleans the objects cache and executes the default behaviour.
|
320
|
+
def reload *args
|
321
|
+
@cached_objects = {}
|
322
|
+
super
|
323
|
+
end
|
324
|
+
|
325
|
+
##
|
326
|
+
# Overwriting duplication method. This method relies on super for any
|
327
|
+
# default behaviour, then duplicate the fields just as their
|
328
|
+
# configuration demands and then allow the object to custimize the
|
329
|
+
# duplication through the duplicate_self method.
|
330
|
+
def dup
|
331
|
+
new_self = super
|
332
|
+
|
333
|
+
# Now we recover all the fields that must be duplicated here
|
334
|
+
fields_to_duplicate.keys.each do |field_to_duplicate|
|
335
|
+
new_self.duplicate_field field_to_duplicate
|
336
|
+
end
|
337
|
+
|
338
|
+
# And allow the class itself to append some behaviour
|
339
|
+
duplicate_self new_self
|
340
|
+
|
341
|
+
new_self
|
342
|
+
end
|
343
|
+
|
344
|
+
##
|
345
|
+
# This method allows us to introduce some custom duplication for each
|
346
|
+
# class that includes the concern.
|
347
|
+
#
|
348
|
+
# Basic behaviour is... doing nothing
|
349
|
+
def duplicate_self new_self
|
350
|
+
end
|
351
|
+
|
352
|
+
##
|
353
|
+
# This method returns a list of the fields to duplicate in this
|
354
|
+
# object. In the concern we will use all the fields and if the classes
|
355
|
+
# need to modify it they will.
|
356
|
+
#
|
357
|
+
# Notice that if the behaviour is that when duplicating the field is
|
358
|
+
# nullfied we will return the field here and the duplicate_field will
|
359
|
+
# manage it properly.
|
360
|
+
def fields_to_duplicate
|
361
|
+
fields_configuration
|
362
|
+
end
|
363
|
+
|
364
|
+
##
|
365
|
+
# When dupping we need to overwrite the cached_objects attribute.
|
366
|
+
# Otherwise the cached_object from the original object would start to
|
367
|
+
# be populated with the objects of the dupped one.
|
368
|
+
def initialize_dup(other)
|
369
|
+
@cached_objects = {}
|
370
|
+
super
|
371
|
+
end
|
372
|
+
|
373
|
+
private
|
374
|
+
|
375
|
+
##
|
376
|
+
# Initializes both the fields_info hash and the objects cache.
|
377
|
+
def set_blank_fields
|
378
|
+
@fields_info ||= {}
|
379
|
+
@cached_objects ||= {}
|
380
|
+
end
|
381
|
+
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|