constructor-pages 1.0.0beta1 → 1.0.0beta2
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/app/assets/javascripts/constructor_pages/urlify.js +1 -0
- data/app/controllers/constructor_pages/fields_controller.rb +22 -28
- data/app/controllers/constructor_pages/pages_controller.rb +19 -48
- data/app/controllers/constructor_pages/templates_controller.rb +8 -20
- data/app/helpers/constructor_pages/fields_helper.rb +0 -2
- data/app/helpers/constructor_pages/pages_helper.rb +2 -9
- data/app/models/constructor_pages/field.rb +24 -10
- data/app/models/constructor_pages/page.rb +10 -13
- data/app/models/constructor_pages/template.rb +5 -4
- data/app/models/constructor_pages/types/boolean_type.rb +0 -2
- data/app/models/constructor_pages/types/date_type.rb +0 -2
- data/app/models/constructor_pages/types/float_type.rb +0 -2
- data/app/models/constructor_pages/types/html_type.rb +0 -2
- data/app/models/constructor_pages/types/image_type.rb +0 -2
- data/app/models/constructor_pages/types/integer_type.rb +0 -2
- data/app/models/constructor_pages/types/string_type.rb +0 -2
- data/app/models/constructor_pages/types/text_type.rb +0 -2
- data/app/views/constructor_pages/fields/_form.html.slim +4 -4
- data/app/views/constructor_pages/fields/types/_boolean.html.slim +1 -0
- data/app/views/constructor_pages/fields/types/_html.html.slim +1 -1
- data/app/views/constructor_pages/fields/types/_string.html.slim +1 -1
- data/app/views/constructor_pages/fields/types/_text.html.slim +1 -1
- data/app/views/constructor_pages/pages/_form.html.slim +5 -8
- data/app/views/constructor_pages/pages/index.html.slim +2 -3
- data/app/views/constructor_pages/templates/_form.html.slim +0 -4
- data/config/locales/en.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/routes.rb +1 -1
- data/constructor-pages.gemspec +1 -2
- data/db/migrate/10_create_html_types.rb +1 -5
- data/db/migrate/11_create_image_types.rb +1 -5
- data/db/migrate/12_add_default_template.rb +3 -3
- data/db/migrate/14_remove_child_id_from_templates.rb +2 -6
- data/db/migrate/15_rename_link_to_redirect.rb +1 -5
- data/db/migrate/16_add_indexes.rb +13 -0
- data/db/migrate/1_create_pages.rb +12 -16
- data/db/migrate/2_create_templates.rb +1 -5
- data/db/migrate/3_create_fields.rb +1 -5
- data/db/migrate/4_create_string_types.rb +2 -6
- data/db/migrate/5_create_float_types.rb +2 -6
- data/db/migrate/6_create_boolean_types.rb +2 -6
- data/db/migrate/7_create_integer_types.rb +2 -6
- data/db/migrate/8_create_text_types.rb +1 -5
- data/db/migrate/9_create_date_types.rb +2 -6
- data/lib/constructor-pages.rb +1 -0
- data/spec/features/constructor_pages/fields_spec.rb +5 -6
- data/spec/features/constructor_pages/pages_spec.rb +26 -63
- data/spec/features/constructor_pages/templates_spec.rb +15 -28
- data/spec/models/constructor_pages/field_spec.rb +0 -2
- data/spec/models/constructor_pages/page_spec.rb +15 -31
- data/spec/models/constructor_pages/template_spec.rb +0 -2
- data/spec/models/constructor_pages/types/boolean_type_spec.rb +0 -2
- data/spec/models/constructor_pages/types/date_type_spec.rb +0 -2
- data/spec/models/constructor_pages/types/float_type_spec.rb +0 -5
- data/spec/models/constructor_pages/types/html_type_spec.rb +0 -2
- data/spec/models/constructor_pages/types/integer_type_spec.rb +0 -2
- data/spec/models/constructor_pages/types/string_type_spec.rb +0 -2
- data/spec/models/constructor_pages/types/text_type_spec.rb +0 -2
- metadata +19 -7
- data/app/helpers/constructor_pages/code_name_uniq.rb +0 -7
- data/app/helpers/constructor_pages/for_select.rb +0 -13
- data/app/helpers/constructor_pages/templates_helper.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f675af9c0fbb73b082bfa366e4f96428ef9c9b0e
|
4
|
+
data.tar.gz: 6c2a949553d8d3aca605e8b7b5e9c19fcb045139
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c012caaa5894b41848bed34798e3a9dbdbe98690321eb5eb2e2b3546a83b4545ed04b83f4b1f1070198dd77f8c6a38b7efd46c840618161a4dbdaf91241a946a
|
7
|
+
data.tar.gz: 17091449e7387cf48d44d91005c6391be092434e92715bd4d3696c6f6d531a6dda1cdd33efb88aee8b95feefeebb31830b0cee9c9687cd2bb352ad9420189ae3
|
@@ -69,6 +69,7 @@ function URLify(s, num_chars) {
|
|
69
69
|
s = s.replace(/[^-\w\s]/g, '-'); // remove unneeded chars
|
70
70
|
s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
|
71
71
|
s = s.replace(/[-\s]+/g, '-'); // convert spaces to hyphens
|
72
|
+
s = s.replace(/^-+|-+$/g, ''); // trim leading/trailing hyphens
|
72
73
|
s = s.toLowerCase(); // convert to lowercase
|
73
74
|
return s.substring(0, num_chars);// trim to first num_chars chars
|
74
75
|
}
|
@@ -1,68 +1,62 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ConstructorPages
|
4
2
|
class FieldsController < ConstructorCore::ApplicationController
|
5
3
|
include TheSortableTreeController::Rebuild
|
6
4
|
include TheSortableTreeController::ExpandNode
|
7
5
|
|
6
|
+
before_action :set_field, only: [:edit, :update, :destroy]
|
7
|
+
|
8
8
|
def new
|
9
|
-
@field = Field.new
|
9
|
+
@field = Field.new template_id: params[:template_id]
|
10
10
|
end
|
11
11
|
|
12
12
|
def edit
|
13
|
-
@field = Field.find(params[:id]).tap {|f| @template = f.template = Template.find(params[:template_id])}
|
14
13
|
end
|
15
14
|
|
16
15
|
def create
|
17
16
|
@field = Field.new field_params
|
18
|
-
@template = @field.template
|
19
17
|
|
20
18
|
if @field.save
|
21
|
-
redirect_to edit_template_path(@template), notice: t(:field_success_added, name: @field.name)
|
19
|
+
redirect_to edit_template_path(@field.template), notice: t(:field_success_added, name: @field.name)
|
22
20
|
else
|
23
|
-
render
|
21
|
+
render :new
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|
27
25
|
def update
|
28
|
-
@field = Field.find params[:id]
|
29
|
-
@template = @field.template
|
30
|
-
|
31
26
|
unless @field.type_value == params[:field][:type_value]
|
32
27
|
@field.type_class.where(field_id: @field.id).each do |field|
|
33
|
-
"constructor_pages/types/#{params[:field][:type_value]}_type".classify.constantize.new(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
28
|
+
_field = "constructor_pages/types/#{params[:field][:type_value]}_type".classify.constantize.new(field_id: @field.id, page_id: field.page_id)
|
29
|
+
|
30
|
+
unless [@field.type_value, params[:field][:type_value]].include?('image') && (@field.type_value == 'string' && field.value.strip == '')
|
31
|
+
_field.value = field.value
|
32
|
+
end
|
33
|
+
|
34
|
+
_field.save
|
35
|
+
field.destroy
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
42
39
|
if @field.update field_params
|
43
|
-
redirect_to edit_template_path(@template.id), notice: t(:field_success_updated, name: @field.name)
|
40
|
+
redirect_to edit_template_path(@field.template.id), notice: t(:field_success_updated, name: @field.name)
|
44
41
|
else
|
45
|
-
render
|
42
|
+
render :edit
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
49
46
|
def destroy
|
50
|
-
@field = Field.find(params[:id])
|
51
|
-
name, template = @field.name, @field.template.id
|
52
47
|
@field.destroy
|
53
|
-
redirect_to edit_template_url(template), notice: t(:field_success_removed, name: name)
|
48
|
+
redirect_to edit_template_url(@field.template), notice: t(:field_success_removed, name: @field.name)
|
54
49
|
end
|
55
50
|
|
56
|
-
def sortable_model
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def sortable_collection
|
61
|
-
ConstructorPages::Field
|
62
|
-
end
|
51
|
+
def sortable_model; Field end
|
52
|
+
def sortable_collection; ConstructorPages::Field end
|
63
53
|
|
64
54
|
private
|
65
55
|
|
56
|
+
def set_field
|
57
|
+
@field = Field.find params[:id]
|
58
|
+
end
|
59
|
+
|
66
60
|
def field_params
|
67
61
|
params.require(:field).permit(
|
68
62
|
:name,
|
@@ -1,95 +1,71 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ConstructorPages
|
4
2
|
class PagesController < ConstructorCore::ApplicationController
|
5
3
|
include TheSortableTreeController::Rebuild
|
6
4
|
include TheSortableTreeController::ExpandNode
|
7
5
|
|
8
|
-
|
6
|
+
skip_before_filter :authenticate_user!, only: [:show]
|
9
7
|
|
10
|
-
|
8
|
+
before_action :set_page, only: [:edit, :update, :destroy]
|
11
9
|
|
12
10
|
def index
|
13
|
-
@pages = Page.
|
14
|
-
@pages_cache = Digest::MD5.hexdigest(@pages.map{|p| [p.id, p.name, p.full_url, p.in_url, p.template.lft, p.lft, p.template_id]}.join)
|
15
|
-
@template_exists = Template.count != 0
|
16
|
-
flash[:notice] = 'Create at least one template' unless @template_exists
|
11
|
+
@pages = Page.roots
|
17
12
|
end
|
18
13
|
|
19
14
|
def new
|
20
|
-
@page = Page.new
|
15
|
+
@page, @templates = Page.new, Template.all
|
16
|
+
|
17
|
+
if @templates.blank?
|
18
|
+
redirect_to pages_path, notice: t(:create_template_first)
|
19
|
+
end
|
21
20
|
end
|
22
21
|
|
23
22
|
def show
|
24
|
-
|
25
|
-
|
26
|
-
error_404 and return if @page.nil? or (!@page.published? and _request != '/')
|
23
|
+
@page = Page.find_by_path request.path
|
24
|
+
|
27
25
|
redirect_to(@page.redirect) && return if @page.redirect?
|
26
|
+
|
28
27
|
_code_name = @page.template.code_name
|
29
28
|
instance_variable_set('@'+_code_name, @page)
|
30
29
|
|
31
|
-
|
32
|
-
format.html { render "#{_code_name.pluralize}/show" rescue render "templates/#{_code_name}"}
|
33
|
-
format.json { render "#{_code_name.pluralize}/show.json", layout: false rescue render json: @page }
|
34
|
-
format.xml { render "#{_code_name.pluralize}/show.xml", layout: false rescue render xml: @page }
|
35
|
-
end
|
30
|
+
render "templates/#{_code_name}", layout: 'application'
|
36
31
|
end
|
37
32
|
|
38
33
|
def edit
|
39
|
-
@page = Page.find(params[:id])
|
40
|
-
@parent_id, @template_id = @page.parent.try(:id), @page.template.id
|
41
|
-
_code_name = @page.template.code_name.pluralize
|
42
|
-
render "#{_code_name}/edit" rescue render :edit
|
43
34
|
end
|
44
35
|
|
45
36
|
def create
|
46
37
|
@page = Page.new page_params
|
47
38
|
|
48
39
|
if @page.save
|
49
|
-
@page.touch_branch
|
50
40
|
redirect_to pages_path, notice: t(:page_success_added, name: @page.name)
|
51
41
|
else
|
52
|
-
|
53
|
-
_template = Template.find(@page.template_id)
|
54
|
-
_code_name = _template.code_name.pluralize if _template
|
55
|
-
render "#{_code_name}/new" rescue render :new
|
56
|
-
else
|
57
|
-
render :new
|
58
|
-
end
|
42
|
+
render :new
|
59
43
|
end
|
60
44
|
end
|
61
45
|
|
62
46
|
def update
|
63
|
-
@page = Page.find params[:id]
|
64
|
-
|
65
|
-
_template_changed = @page.template.id != params[:page][:template_id].to_i
|
66
|
-
|
67
|
-
@page.remove_fields_values if _template_changed
|
68
|
-
|
69
47
|
if @page.update page_params
|
70
|
-
@page.create_fields_values if _template_changed
|
71
48
|
@page.update_fields_values params[:fields]
|
72
|
-
@page.touch_branch
|
73
49
|
|
74
50
|
redirect_to pages_path, notice: t(:page_success_updated, name: @page.name)
|
75
51
|
else
|
76
|
-
render
|
52
|
+
render :edit
|
77
53
|
end
|
78
54
|
end
|
79
55
|
|
80
56
|
def destroy
|
81
|
-
@page = Page.find(params[:id])
|
82
|
-
@page.touch_branch
|
83
57
|
@page.destroy
|
84
58
|
redirect_to pages_path, notice: t(:page_success_removed, name: @page.name)
|
85
59
|
end
|
86
60
|
|
87
|
-
def sortable_model
|
88
|
-
Page
|
89
|
-
end
|
61
|
+
def sortable_model; Page end
|
90
62
|
|
91
63
|
private
|
92
64
|
|
65
|
+
def set_page
|
66
|
+
@page = Page.find params[:id]
|
67
|
+
end
|
68
|
+
|
93
69
|
def page_params
|
94
70
|
params.require(:page).permit(
|
95
71
|
:active,
|
@@ -99,7 +75,6 @@ module ConstructorPages
|
|
99
75
|
:keywords,
|
100
76
|
:description,
|
101
77
|
:auto_url,
|
102
|
-
:parent_id,
|
103
78
|
:template_id,
|
104
79
|
:in_nav,
|
105
80
|
:in_map,
|
@@ -108,9 +83,5 @@ module ConstructorPages
|
|
108
83
|
:redirect
|
109
84
|
)
|
110
85
|
end
|
111
|
-
|
112
|
-
def error_404
|
113
|
-
render file: "#{Rails.root}/public/404", layout: false, status: :not_found
|
114
|
-
end
|
115
86
|
end
|
116
87
|
end
|
@@ -1,15 +1,12 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ConstructorPages
|
4
2
|
class TemplatesController < ConstructorCore::ApplicationController
|
5
3
|
include TheSortableTreeController::Rebuild
|
6
4
|
include TheSortableTreeController::ExpandNode
|
7
5
|
|
8
|
-
|
6
|
+
before_action :set_template, only: [:edit, :update, :destroy]
|
9
7
|
|
10
8
|
def index
|
11
9
|
@templates = Template.roots
|
12
|
-
@templates_cache = Digest::MD5.hexdigest(@templates.map{|t| [t.id, t.name, t.lft]}.join)
|
13
10
|
end
|
14
11
|
|
15
12
|
def new
|
@@ -17,7 +14,6 @@ module ConstructorPages
|
|
17
14
|
end
|
18
15
|
|
19
16
|
def edit
|
20
|
-
@template = Template.find(params[:id])
|
21
17
|
end
|
22
18
|
|
23
19
|
def create
|
@@ -31,8 +27,6 @@ module ConstructorPages
|
|
31
27
|
end
|
32
28
|
|
33
29
|
def update
|
34
|
-
@template = Template.find params[:id]
|
35
|
-
|
36
30
|
if @template.update template_params
|
37
31
|
redirect_to templates_url, notice: t(:template_success_updated, name: @template.name)
|
38
32
|
else
|
@@ -41,28 +35,22 @@ module ConstructorPages
|
|
41
35
|
end
|
42
36
|
|
43
37
|
def destroy
|
44
|
-
@template
|
45
|
-
|
46
|
-
if @template.pages.count == 0
|
47
|
-
name = @template.name
|
48
|
-
@template.destroy
|
49
|
-
redirect_to templates_url, notice: t(:template_success_removed, name: name)
|
50
|
-
else
|
51
|
-
redirect_to :back, alert: t(:template_error_delete_pages)
|
52
|
-
end
|
38
|
+
@template.destroy
|
39
|
+
redirect_to templates_url, notice: t(:template_success_removed, name: @template.name)
|
53
40
|
end
|
54
41
|
|
55
|
-
def sortable_model
|
56
|
-
Template
|
57
|
-
end
|
42
|
+
def sortable_model; Template end
|
58
43
|
|
59
44
|
private
|
60
45
|
|
46
|
+
def set_template
|
47
|
+
@template = Template.find params[:id]
|
48
|
+
end
|
49
|
+
|
61
50
|
def template_params
|
62
51
|
params.require(:template).permit(
|
63
52
|
:name,
|
64
53
|
:code_name,
|
65
|
-
:parent_id,
|
66
54
|
:child_id
|
67
55
|
)
|
68
56
|
end
|
@@ -1,14 +1,7 @@
|
|
1
1
|
module ConstructorPages
|
2
2
|
module PagesHelper
|
3
|
-
|
4
|
-
|
5
|
-
def templates
|
6
|
-
Template.all.map{|t| ["#{'--'*t.level} #{t.name}", t.id]}
|
7
|
-
end
|
8
|
-
|
9
|
-
def image_tag_with_at2x(name_at_1x, options={})
|
10
|
-
name_at_2x = name_at_1x.gsub(%r{\.\w+$}, '@2x\0')
|
11
|
-
image_tag(name_at_1x, options.merge("data-at2x" => asset_path(name_at_2x)))
|
3
|
+
def templates_tree(templates)
|
4
|
+
templates.map{|t| ["#{'--'*t.level} #{t.name}", t.id]}
|
12
5
|
end
|
13
6
|
end
|
14
7
|
end
|
@@ -1,15 +1,11 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ConstructorPages
|
4
2
|
# Field model. Fields allows to add custom fields for template.
|
5
3
|
# Each field has type of value such as float, integer, string...
|
6
4
|
class Field < ActiveRecord::Base
|
7
|
-
# Adding code_name_uniqueness method
|
8
|
-
include CodeNameUniq
|
9
|
-
|
10
5
|
# Array of available field types
|
11
|
-
TYPES = %w{string integer float boolean text date html image}
|
12
|
-
|
6
|
+
TYPES = %w{string integer float boolean text date html image}
|
7
|
+
|
8
|
+
TYPES.each {|t| class_eval %{has_many :#{t}_types, class_name: 'Types::#{t.titleize}Type'} }
|
13
9
|
|
14
10
|
validates_presence_of :name
|
15
11
|
validates_uniqueness_of :code_name, scope: :template_id
|
@@ -47,6 +43,11 @@ module ConstructorPages
|
|
47
43
|
|
48
44
|
private
|
49
45
|
|
46
|
+
# Check if code_name is not available
|
47
|
+
def code_name_uniqueness
|
48
|
+
errors.add(:base, :code_name_already_in_use) unless Page.check_code_name(code_name) and check_code_name(code_name)
|
49
|
+
end
|
50
|
+
|
50
51
|
# Check if there is code_name in template branch
|
51
52
|
def check_code_name(code_name)
|
52
53
|
[code_name.pluralize, code_name.singularize].each {|name|
|
@@ -55,8 +56,21 @@ module ConstructorPages
|
|
55
56
|
true
|
56
57
|
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
def create_page_fields
|
60
|
+
template.page_ids.each_slice(500) do |batch|
|
61
|
+
_items = []
|
62
|
+
batch.each do |_id|
|
63
|
+
_items << type_class.new({page_id: _id, field_id: id})
|
64
|
+
end
|
65
|
+
type_class.import _items
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def destroy_all_page_fields
|
70
|
+
template.page_ids.each_slice(1000) do |batch|
|
71
|
+
type_class.where(page_id: batch, field_id: id).delete_all
|
72
|
+
Page.update_all({updated_at: Time.now}, {id: batch})
|
73
|
+
end
|
74
|
+
end
|
61
75
|
end
|
62
76
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module ConstructorPages
|
4
2
|
# Page model. Pages are core for company websites, blogs etc.
|
5
3
|
class Page < ActiveRecord::Base
|
@@ -14,9 +12,12 @@ module ConstructorPages
|
|
14
12
|
has_many :fields, through: :template
|
15
13
|
belongs_to :template
|
16
14
|
|
15
|
+
scope :published, -> { where(active: true) }
|
16
|
+
|
17
17
|
default_scope -> { order :lft }
|
18
18
|
|
19
19
|
validate :templates_existing_check
|
20
|
+
validate :check_template_changing, on: :update
|
20
21
|
|
21
22
|
before_save :friendly_url, :assign_template, :full_url_update
|
22
23
|
after_update :descendants_update
|
@@ -25,10 +26,10 @@ module ConstructorPages
|
|
25
26
|
acts_as_nested_set
|
26
27
|
|
27
28
|
class << self
|
28
|
-
# Used for find page by request. It return first page if no request given or request is home page
|
29
|
+
# Used for find page by request path. It return first page if no request given or request is home page
|
29
30
|
# @param request for example <tt>'/conditioners/split-systems/zanussi'</tt>
|
30
|
-
def
|
31
|
-
|
31
|
+
def find_by_path(path)
|
32
|
+
path == '/' ? Page.published.first! : Page.published.find_by!(full_url: path)
|
32
33
|
end
|
33
34
|
|
34
35
|
# Generate full_url from parent id and url
|
@@ -129,12 +130,10 @@ module ConstructorPages
|
|
129
130
|
|
130
131
|
# Update all fields values with given params.
|
131
132
|
# @param params should looks like <tt>{price: 500, content: 'Hello'}</tt>
|
132
|
-
|
133
|
-
def update_fields_values(params, reset_booleans = true)
|
133
|
+
def update_fields_values(params)
|
134
134
|
params || return
|
135
135
|
|
136
136
|
fields.each {|f| f.find_or_create_type_object(self).tap {|t| t || next
|
137
|
-
t.value = 0 if f.type_value == 'boolean' && reset_booleans
|
138
137
|
params[f.code_name.to_sym].tap {|v| v && t.value = v}
|
139
138
|
t.save }}
|
140
139
|
end
|
@@ -184,11 +183,6 @@ module ConstructorPages
|
|
184
183
|
# Check if link specified
|
185
184
|
def redirect?; url != redirect && !redirect.empty? end
|
186
185
|
|
187
|
-
# Touch all pages in same branch
|
188
|
-
def touch_branch
|
189
|
-
[ancestors, descendants].each {|p| p.map(&:touch)}
|
190
|
-
end
|
191
|
-
|
192
186
|
# When method missing it get/set field value or get page in branch
|
193
187
|
#
|
194
188
|
# Examples:
|
@@ -211,6 +205,9 @@ module ConstructorPages
|
|
211
205
|
# Page is not valid if there is no template
|
212
206
|
def templates_existing_check; errors.add_on_empty(:template_id) if Template.count == 0 end
|
213
207
|
|
208
|
+
# Page should not change template
|
209
|
+
def check_template_changing; errors.add(:base, :can_not_change_template) if template_id_changed? end
|
210
|
+
|
214
211
|
# If template_id is nil then get first template
|
215
212
|
def assign_template; self.template_id = Template.first.id unless template_id end
|
216
213
|
|