tramway-core 1.17.1 → 1.17.2.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/README.md +83 -2
- data/app/assets/javascripts/tramway/core/application.js +1 -1
- data/app/controllers/tramway/core/application_controller.rb +8 -12
- data/app/decorators/tramway/core/application_decorator.rb +16 -28
- data/app/decorators/tramway/core/associations/class_helper.rb +13 -13
- data/app/decorators/tramway/core/associations/object_helper.rb +31 -3
- data/app/decorators/tramway/core/attributes/view_helper.rb +26 -0
- data/app/decorators/tramway/core/concerns/attributes_decorator_helper.rb +47 -26
- data/app/decorators/tramway/core/delegating/class_helper.rb +9 -0
- data/app/forms/tramway/core/application_form.rb +83 -171
- data/app/forms/tramway/core/application_forms/association_object_helpers.rb +31 -0
- data/app/forms/tramway/core/application_forms/constant_class_actions.rb +7 -0
- data/app/forms/tramway/core/application_forms/constant_object_actions.rb +13 -0
- data/app/forms/tramway/core/application_forms/properties_object_helper.rb +23 -0
- data/app/forms/tramway/core/extendable_form.rb +3 -70
- data/app/forms/tramway/core/extendable_forms_helpers/class_builder.rb +34 -0
- data/app/forms/tramway/core/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
- data/app/forms/tramway/core/extendable_forms_helpers/more_properties_helper.rb +27 -0
- data/app/forms/tramway/core/extendable_forms_helpers/properties_helper.rb +16 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/class_helpers.rb +18 -0
- data/app/forms/tramway/core/extendable_forms_helpers/submit/object_helpers.rb +7 -0
- data/app/forms/tramway/core/extendable_forms_helpers/validators.rb +40 -0
- data/app/helpers/tramway/core/copy_to_clipboard_helper.rb +6 -10
- data/app/helpers/tramway/core/title_helper.rb +17 -22
- data/app/models/tramway/core/application_record.rb +38 -40
- data/app/uploaders/image_defaults.rb +2 -1
- data/app/uploaders/photo_uploader.rb +8 -8
- data/config/initializers/plurals.rb +2 -2
- data/lib/tramway/collection.rb +4 -6
- data/lib/tramway/collections.rb +4 -0
- data/lib/tramway/collections/helper.rb +15 -14
- data/lib/tramway/core.rb +22 -22
- data/lib/tramway/core/engine.rb +4 -8
- data/lib/tramway/core/generators.rb +4 -0
- data/lib/tramway/core/generators/install_generator.rb +17 -17
- data/lib/tramway/core/version.rb +1 -1
- data/lib/tramway/error.rb +12 -1
- data/lib/yaml/errors.yml +35 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e25693262017e7eb7b500db8ed733e26ed5c841f4e5eca94b036f422114c8f8e
|
4
|
+
data.tar.gz: 9cc1274352800f545610e01d2c02485c3ef2837bd2d413041818462682496e04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 796e723d4c64a741d72b2d25a769e1344d895805dda3ba55da9c6f4161252a416ade82f2439217599a60605c6d29e6292be4b165a56f0c26343eeeba6ca9ce85
|
7
|
+
data.tar.gz: 9991a6ecf790a5ce4ed3b0064d3cc2392336359bcf095416b91a9ee6d152e19d1487826ab9a85d7c1df4913a426375128955c602b1501ff5b273319ca49db211
|
data/README.md
CHANGED
@@ -33,7 +33,53 @@ Tramway::Core.initialize_application model_class: ::Tramway::Conference::Unity #
|
|
33
33
|
Rails.application.config.assets.precompile += %w( *.jpg *.png *.js )
|
34
34
|
```
|
35
35
|
# Usage
|
36
|
+
|
36
37
|
## Decorators
|
38
|
+
### Associations
|
39
|
+
|
40
|
+
Your can decorate association models. Supporting all types of association
|
41
|
+
|
42
|
+
*app/decorators/your_model_decorator.rb*
|
43
|
+
```ruby
|
44
|
+
class YourModelDecorator < Tramway::Core::ApplicationDecorator
|
45
|
+
decorate_association :some_model
|
46
|
+
decorate_association :another_model, decorator: SpecificDecoratorForThisCase
|
47
|
+
decorate_association :another_one_model, as: :repeat_here_as_parameter_from_model
|
48
|
+
decorate_association :something_else_model, state_machines: [ :here_array_of_state_machines_you_want_to_see_in_YourModel_show_page ] # support from tramway-admin gem
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
You can decorate a lot of models in one line
|
53
|
+
|
54
|
+
*app/decorators/your_model_decorator.rb*
|
55
|
+
```ruby
|
56
|
+
class YourModelDecorator < Tramway::Core::ApplicationDecorator
|
57
|
+
decorate_associations :some_model, :another_model, :another_one_model, :something_else_model
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
Also, you can configurate what associations you want to see in YourModel page in admin panel *support only for [tramway-admin](https://rubygems.org/gems/tramway-admin) gem*
|
62
|
+
|
63
|
+
*app/decorators/your_model_decorator.rb*
|
64
|
+
```ruby
|
65
|
+
class YourModelDecorator < Tramway::Core::ApplicationDecorator
|
66
|
+
class << self
|
67
|
+
def show_associations
|
68
|
+
[ :some_model, :another_model, :another_one_model ]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### Delegating attributes
|
75
|
+
|
76
|
+
*app/decorators/your_model_decorator.rb*
|
77
|
+
```ruby
|
78
|
+
class YourModelDecorator < Tramway::Core::ApplicationDecorator
|
79
|
+
delegate_attributes :title, :something_else, :another_atttribute
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
37
83
|
### Helper methods
|
38
84
|
|
39
85
|
#### date_view
|
@@ -106,6 +152,39 @@ Something like this:
|
|
106
152
|
copy_to_clipboard "some_id" # some_id is HTML id of element. Content of this element will be copied to the clipboard after pressing the button
|
107
153
|
```
|
108
154
|
|
155
|
+
## How to create model that will be an Application Model for the Tramway
|
156
|
+
|
157
|
+
#### 1. Generate model that you to use. We create Organization, for example
|
158
|
+
|
159
|
+
```shell
|
160
|
+
rails g model organization name:text public_name:text tagline:text address:text phone:text coordinates:point, state: text # remember! State field is required, if you use tramway-admin
|
161
|
+
rails db:migrate
|
162
|
+
```
|
163
|
+
|
164
|
+
#### 2. Add model_class to Initializer
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
Tramway::Core.initialize_application model_class: Organization
|
168
|
+
```
|
169
|
+
|
170
|
+
#### 3. Create 1 instance of Organization model
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
rails c
|
174
|
+
Organization.create! public_name: 'Tramway', name: :organization, tagline: 'Tramway is not buggy, LOL!'
|
175
|
+
```
|
176
|
+
|
177
|
+
#### 4. Add model to singleton to the `tramway-admin` admin panel to be able to change its data
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
Tramway::Admin.set_singleton_models Organization, project: :organization # now you should use organization.name here
|
181
|
+
```
|
182
|
+
|
183
|
+
#### 5. Then continue configuration of your model in admin panel with tramway-admin gem [instruction, starting from point 8](https://github.com/ulmic/tramway-dev/tree/develop/tramway-admin#8-configurate-navbar)
|
184
|
+
|
185
|
+
#### 6. Now you are able to change your application main info in admin panel
|
186
|
+
|
187
|
+
## In Russian
|
109
188
|
|
110
189
|
# Базовые классы
|
111
190
|
|
@@ -124,8 +203,10 @@ copy_to_clipboard "some_id" # some_id is HTML id of element. Content of this ele
|
|
124
203
|
* models - часто используемые в моделях слова
|
125
204
|
* state_machines - локализация состояний
|
126
205
|
|
127
|
-
##
|
128
|
-
|
206
|
+
## Contributors
|
207
|
+
|
208
|
+
* [Pavel Kalashnikov](https://github.com/kalashnikovisme)
|
209
|
+
* [moshinaan](https://github.com/moshinaan)
|
129
210
|
|
130
211
|
## License
|
131
212
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -28,7 +28,7 @@ $(document).ready(function() {
|
|
28
28
|
console.log('You should set `window.current_locale` before all Javascript code');
|
29
29
|
}
|
30
30
|
|
31
|
-
if ($('.date_picker').length
|
31
|
+
if ($('.date_picker').length != 0) {
|
32
32
|
$('.date_picker').datepicker({
|
33
33
|
format: window.current_locale.date_format,
|
34
34
|
language: window.current_locale.locale
|
@@ -1,18 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
before_action :application
|
7
|
-
before_action :load_extensions
|
3
|
+
class Tramway::Core::ApplicationController < ActionController::Base
|
4
|
+
before_action :application
|
5
|
+
before_action :load_extensions
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def application
|
8
|
+
@application = ::Tramway::Core.application_object
|
9
|
+
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
11
|
+
def load_extensions
|
12
|
+
::Tramway::Extensions.load if defined? ::Tramway::Extensions
|
17
13
|
end
|
18
14
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'tramway/error'
|
4
|
+
require 'tramway/helpers/class_name_helpers'
|
4
5
|
|
5
6
|
class Tramway::Core::ApplicationDecorator
|
6
7
|
include ActionView::Helpers
|
@@ -8,6 +9,8 @@ class Tramway::Core::ApplicationDecorator
|
|
8
9
|
include ::FontAwesome5::Rails::IconHelper
|
9
10
|
include ::Tramway::Core::CopyToClipboardHelper
|
10
11
|
include ::Tramway::Core::Associations::ObjectHelper
|
12
|
+
include ::Tramway::Core::Attributes::ViewHelper
|
13
|
+
include ::Tramway::ClassNameHelpers
|
11
14
|
|
12
15
|
def initialize(object)
|
13
16
|
@object = object
|
@@ -18,12 +21,18 @@ class Tramway::Core::ApplicationDecorator
|
|
18
21
|
end
|
19
22
|
|
20
23
|
def title
|
21
|
-
|
22
|
-
|
24
|
+
Tramway::Error.raise_error(
|
25
|
+
:tramway, :core, :application_decorator, :title, :please_implement_title,
|
26
|
+
class_name: self.class, object_class: object.class
|
27
|
+
)
|
23
28
|
end
|
24
29
|
|
30
|
+
delegate :id, to: :object
|
31
|
+
delegate :human_state_name, to: :object
|
32
|
+
|
25
33
|
class << self
|
26
34
|
include ::Tramway::Core::Associations::ClassHelper
|
35
|
+
include ::Tramway::Core::Delegating::ClassHelper
|
27
36
|
|
28
37
|
def collections
|
29
38
|
[:all]
|
@@ -61,19 +70,11 @@ class Tramway::Core::ApplicationDecorator
|
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
64
|
-
delegate :id, to: :object
|
65
|
-
delegate :human_state_name, to: :object
|
66
|
-
|
67
73
|
def link
|
68
74
|
if object.try :file
|
69
75
|
object.file.url
|
70
76
|
else
|
71
|
-
|
72
|
-
plugin: :core,
|
73
|
-
method: :link,
|
74
|
-
message: "Method `link` uses `file` attribute of the decorated object. If decorated object doesn't contain `file`, you shouldn't use `link` method."
|
75
|
-
)
|
76
|
-
raise error.message
|
77
|
+
Tramway::Error.raise_error :tramway, :core, :application_decorator, :link, :method_link_uses_file_attribute
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
@@ -96,25 +97,12 @@ class Tramway::Core::ApplicationDecorator
|
|
96
97
|
def attributes
|
97
98
|
object.attributes.reduce({}) do |hash, attribute|
|
98
99
|
if attribute[0].in? RESERVED_WORDS
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
message: "Method `#{attribute[0]}` is reserved word. Please, create or delegate method in #{self.class.name} with another name."
|
100
|
+
Tramway::Error.raise_error(
|
101
|
+
:tramway, :core, :application_decorator, :attributes, :method_is_reserved_word,
|
102
|
+
attribute_name: attribute[0], class_name: self.class.name
|
103
103
|
)
|
104
|
-
raise error.message
|
105
|
-
end
|
106
|
-
value = try(attribute[0]) ? send(attribute[0]) : object.send(attribute[0])
|
107
|
-
if attribute[0].to_s.in? object.class.state_machines.keys.map(&:to_s)
|
108
|
-
hash.merge! attribute[0] => state_machine_view(object, attribute[0])
|
109
|
-
elsif value.class.in? [ActiveSupport::TimeWithZone, DateTime, Time]
|
110
|
-
hash.merge! attribute[0] => datetime_view(attribute[1])
|
111
|
-
elsif value.class.superclass == ApplicationUploader
|
112
|
-
hash.merge! attribute[0] => image_view(object.send(attribute[0]))
|
113
|
-
elsif value.is_a? Enumerize::Value
|
114
|
-
hash.merge! attribute[0] => enumerize_view(value)
|
115
|
-
else
|
116
|
-
hash.merge! attribute[0] => value
|
117
104
|
end
|
105
|
+
hash.merge! attribute[0] => build_viewable_value(object, attribute)
|
118
106
|
end
|
119
107
|
end
|
120
108
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tramway::Core::Associations::ClassHelper
|
2
4
|
def decorate_association(association_name, decorator: nil, as: nil, state_machines: [])
|
3
5
|
@@decorated_associations ||= []
|
@@ -14,27 +16,25 @@ module Tramway::Core::Associations::ClassHelper
|
|
14
16
|
end
|
15
17
|
|
16
18
|
define_method "add_#{association_name}_form" do
|
17
|
-
|
19
|
+
add_association_form_class_name(object, association_name).new object
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
def decorate_associations(*association_names)
|
24
|
+
association_names.each do |association_name|
|
25
|
+
decorate_association association_name
|
26
|
+
end
|
27
|
+
end
|
21
28
|
|
22
29
|
def define_main_association_method(association_name, decorator)
|
23
30
|
define_method association_name do
|
24
31
|
association = object.class.reflect_on_association(association_name)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
decorator_class_name = decorator || "#{class_name(association).to_s.singularize}Decorator".constantize
|
30
|
-
if association.class.in? [ ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection ]
|
31
|
-
return object.send(association_name).active.map do |association_object|
|
32
|
-
decorator_class_name.decorate association_object
|
33
|
-
end
|
34
|
-
end
|
35
|
-
if association.class == ActiveRecord::Reflection::BelongsToReflection
|
36
|
-
return decorator_class_name.decorate object.send association_name
|
32
|
+
check_association object, association_name, association
|
33
|
+
decorator_class_name = decorator || decorator_class_name(class_name(association))
|
34
|
+
if association_type(association).in? %i[has_many has_and_belongs_to_many]
|
35
|
+
return associations_collection(object, association_name, decorator_class_name)
|
37
36
|
end
|
37
|
+
return decorator_class_name.decorate object.send association_name if association_type(association) == :belongs_to
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -1,13 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tramway::Core::Associations::ObjectHelper
|
2
4
|
def class_name(association)
|
3
5
|
if association.polymorphic?
|
4
|
-
object.send(
|
6
|
+
object.send(association.name).class
|
5
7
|
else
|
6
8
|
unless association.options[:class_name]
|
7
|
-
|
8
|
-
|
9
|
+
Tramway::Error.raise_error(
|
10
|
+
:tramway, :core, :associations, :object_helper, :please_specify_association_name,
|
11
|
+
association_name: association.name, object_class: object.class,
|
12
|
+
association_class_name: association.name.to_s.singularize.camelize
|
13
|
+
)
|
9
14
|
end
|
10
15
|
association.options[:class_name]
|
11
16
|
end
|
12
17
|
end
|
18
|
+
|
19
|
+
def check_association(object, association_name, association)
|
20
|
+
return unless association.nil?
|
21
|
+
|
22
|
+
Tramway::Error.raise_error(
|
23
|
+
:tramway, :core, :associations, :class_helper, :model_does_not_have_association,
|
24
|
+
object_class: object.class, association_name: association_name
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def association_type(association)
|
29
|
+
association.class.to_s.split('::').last.sub(/Reflection$/, '').underscore.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def associations_collection(object, association_name, decorator_class_name)
|
33
|
+
object.send(association_name).active.map do |association_object|
|
34
|
+
decorator_class_name.decorate association_object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_association_form_class_name(object, association_name)
|
39
|
+
"Admin::#{object.class.to_s.pluralize}::Add#{association_name.to_s.camelize.singularize}Form".constantize
|
40
|
+
end
|
13
41
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Core::Attributes::ViewHelper
|
4
|
+
def build_viewable_value(object, attribute)
|
5
|
+
value = try(attribute[0]) ? send(attribute[0]) : object.send(attribute[0])
|
6
|
+
return state_machine_view(object, attribute[0]) if state_machine? object, attribute[0]
|
7
|
+
|
8
|
+
view_by_value object, value, attribute
|
9
|
+
end
|
10
|
+
|
11
|
+
def state_machine?(object, attribute_name)
|
12
|
+
attribute_name.to_s.in? object.class.state_machines.keys.map(&:to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def view_by_value(object, value, attribute)
|
16
|
+
if value.class.in? [ActiveSupport::TimeWithZone, DateTime, Time]
|
17
|
+
datetime_view(attribute[1])
|
18
|
+
elsif value.class.superclass == ApplicationUploader
|
19
|
+
image_view(object.send(attribute[0]))
|
20
|
+
elsif value.is_a? Enumerize::Value
|
21
|
+
enumerize_view(value)
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -13,37 +13,58 @@ module Tramway::Core::Concerns::AttributesDecoratorHelper
|
|
13
13
|
object.send "human_#{attribute_name}_name"
|
14
14
|
end
|
15
15
|
|
16
|
+
BASE64_REGEXP = %r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|
|
17
|
+
(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$}x.freeze
|
18
|
+
|
16
19
|
def image_view(original, thumb: nil, filename: nil)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
elsif thumb&.match(%r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$})
|
23
|
-
"data:image/jpeg;base64,#{thumb}"
|
24
|
-
else
|
25
|
-
thumb
|
26
|
-
end
|
27
|
-
src_original = if original.is_a?(CarrierWave::Uploader::Base)
|
28
|
-
original.url
|
29
|
-
elsif original.match(%r{^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$})
|
30
|
-
"data:image/jpeg;base64,#{original}"
|
31
|
-
else
|
32
|
-
original
|
33
|
-
end
|
34
|
-
content_tag(:div) do
|
35
|
-
begin
|
36
|
-
concat image_tag src_thumb || src_original
|
37
|
-
rescue NoMethodError => e
|
38
|
-
error = Tramway::Error.new plugin: :core, method: :image_view, message: "You should mount PhotoUploader to your model. Just add `mount_uploader \#{attribute_name}, PhotoUploader` to your model. #{e.message}"
|
39
|
-
raise error.message
|
40
|
-
end
|
41
|
-
concat link_to(fa_icon(:download), src_original, class: 'btn btn-success', download: filename) if filename
|
42
|
-
end
|
20
|
+
return unless original.present?
|
21
|
+
|
22
|
+
filename ||= build_filename(original)
|
23
|
+
content_tag(:div) do
|
24
|
+
build_div_content src_original(original), src_thumb(original, thumb), filename || build_filename(original)
|
43
25
|
end
|
44
26
|
end
|
45
27
|
|
46
28
|
def enumerize_view(value)
|
47
29
|
value.text
|
48
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def src_thumb(original, thumb)
|
35
|
+
thumb ||= original.is_a?(CarrierWave::Uploader::Base) ? original.small : nil
|
36
|
+
if thumb&.is_a?(CarrierWave::Uploader::Base)
|
37
|
+
thumb.url
|
38
|
+
elsif thumb&.match(BASE64_REGEXP)
|
39
|
+
"data:image/jpeg;base64,#{thumb}"
|
40
|
+
else
|
41
|
+
thumb
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def src_original(original)
|
46
|
+
if original.is_a?(CarrierWave::Uploader::Base)
|
47
|
+
original.url
|
48
|
+
elsif original.match(BASE64_REGEXP)
|
49
|
+
"data:image/jpeg;base64,#{original}"
|
50
|
+
else
|
51
|
+
original
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_filename(original)
|
56
|
+
original.is_a?(CarrierWave::Uploader::Base) ? original.path&.split('/')&.last : nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_div_content(original, thumb, filename)
|
60
|
+
begin
|
61
|
+
concat image_tag src_thumb(original, thumb) || src_original(original)
|
62
|
+
rescue NoMethodError => e
|
63
|
+
Tramway::Error.raise_error(
|
64
|
+
:tramway, :core, :concerns, :attributes_decorator_helper, :you_should_mount_photo_uploader,
|
65
|
+
message: e.message, attribute_name: attribute_name
|
66
|
+
)
|
67
|
+
end
|
68
|
+
concat link_to(fa_icon(:download), src_original(original), class: 'btn btn-success', download: filename) if filename
|
69
|
+
end
|
49
70
|
end
|