carload 0.3.0 → 0.4.0
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 +17 -0
- data/app/assets/stylesheets/carload/_select2.scss +15 -0
- data/app/assets/stylesheets/carload/colors.scss.erb +5 -0
- data/app/assets/stylesheets/carload/common.scss +16 -10
- data/app/assets/stylesheets/carload/dashboard.scss +16 -14
- data/app/controllers/carload/dashboard_controller.rb +19 -3
- data/app/helpers/carload/application_helper.rb +16 -0
- data/app/helpers/carload/dashboard_helper.rb +73 -65
- data/app/views/carload/dashboard/_form.html.erb +14 -2
- data/app/views/carload/dashboard/index.html.erb +1 -7
- data/app/views/carload/dashboard/shared/_search_fields.html.erb +6 -10
- data/app/views/layouts/carload/dashboard.html.erb +2 -2
- data/db/migrate/20161030074822_carload_enable_zhparser_extension.rb +7 -0
- data/lib/carload/association_pipelines.rb +52 -0
- data/lib/carload/dashboard.rb +5 -108
- data/lib/carload/engine.rb +49 -0
- data/lib/carload/model_spec.rb +98 -0
- data/lib/carload/version.rb +1 -1
- data/lib/carload.rb +5 -1
- data/lib/generators/carload/dash_generator.rb +19 -18
- data/lib/generators/carload/install_generator.rb +10 -0
- data/lib/generators/carload/templates/carload.rb +14 -2
- metadata +9 -6
- data/app/assets/stylesheets/carload/colors.scss +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9dc8244c3cd30b96538af399c5d325a32c7b46f2
|
4
|
+
data.tar.gz: 038e2a71da51255577b35a15fc21a8b6b66fb7b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a24677546621e1a187042e2e27ea5b603495590543b624133ab06151ddb423e2d7ad07695241277f52f3b9efc212bee433b87583140749be9e91a9693818d23
|
7
|
+
data.tar.gz: 99b19227d0f62ad5ae1081e5fa1deb04becb1373ec97f88f40514d9493e265b3e4bc84907d829afa908bad798287e7c62da828f22c9798fa3f60d18ccf42e770
|
data/README.md
CHANGED
@@ -26,9 +26,24 @@ You can edit the initializer `config/initializers/carload.rb` for example:
|
|
26
26
|
|
27
27
|
```ruby
|
28
28
|
Carload.setup do |config|
|
29
|
+
# Set the title that will be displayed on the browser tab area.
|
30
|
+
config.page.title = nil
|
31
|
+
|
32
|
+
# Set the footer text that will be displayed on each page.
|
33
|
+
config.page.footer = nil
|
34
|
+
|
35
|
+
# Set the colors of page elements.
|
36
|
+
config.page.main_color = nil
|
37
|
+
config.page.text_color = 'black'
|
38
|
+
config.page.button_color = nil
|
39
|
+
config.page.button_text_color = nil
|
40
|
+
|
29
41
|
# Specify which authentication solution is used. Currently, we only support Devise.
|
30
42
|
config.auth_solution = :devise
|
31
43
|
|
44
|
+
# Set which file upload solution is used. Currently, we only support Carrierwave.
|
45
|
+
config.upload_solution = :carrierwave
|
46
|
+
|
32
47
|
# Set the actions used to discern user's permission to access dashboard.
|
33
48
|
#
|
34
49
|
# config.dashboard.permits_user.<method> = '...'
|
@@ -87,6 +102,8 @@ class Dashboard < Carload::Dashboard
|
|
87
102
|
end
|
88
103
|
```
|
89
104
|
|
105
|
+
- You can run another generator `rails g carload:dash <model_name>` to generate the above content automatically (it may ask you some question).
|
106
|
+
|
90
107
|
- Make sure you have the necessary I18n translation files, for example:
|
91
108
|
|
92
109
|
```yaml
|
@@ -15,3 +15,18 @@
|
|
15
15
|
.select2-container {
|
16
16
|
min-width: 174px;
|
17
17
|
}
|
18
|
+
|
19
|
+
.select2-search__field {
|
20
|
+
line-height: 22px;
|
21
|
+
}
|
22
|
+
.select2-search__field:focus {
|
23
|
+
box-shadow: none !important;
|
24
|
+
}
|
25
|
+
.select2-selection__choice {
|
26
|
+
line-height: 22px;
|
27
|
+
background-color: $main-color !important;
|
28
|
+
color: white;
|
29
|
+
}
|
30
|
+
.select2-selection__choice__remove {
|
31
|
+
color: white !important;
|
32
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
$main-color: <%= Carload.page.main_color || '#8C7DA6' %>;
|
2
|
+
$text-color: <%= Carload.page.text_color || '#3F3F44' %>;
|
3
|
+
$button-color-1: <%= Carload.page.button_color_1 || Carload.page.button_color || '#60b044' %>;
|
4
|
+
$button-color-2: <%= Carload.page.button_color_2 || Carload.page.button_color || '#8add6d' %>;
|
5
|
+
$button-text-color: <%= Carload.page.button_text_color || 'white' %>;
|
@@ -51,19 +51,21 @@ th {
|
|
51
51
|
}
|
52
52
|
|
53
53
|
.btn-primary {
|
54
|
-
color:
|
54
|
+
color: $button-text-color;
|
55
55
|
text-shadow: 0 -1px 0 rgba(0,0,0,0.15);
|
56
|
-
background-color:
|
57
|
-
background-image: -webkit-linear-gradient(
|
58
|
-
background-image: linear-gradient(
|
59
|
-
border
|
56
|
+
background-color: $button-color-1;
|
57
|
+
background-image: -webkit-linear-gradient($button-color-2, $button-color-1);
|
58
|
+
background-image: linear-gradient($button-color-2, $button-color-1);
|
59
|
+
border: none;
|
60
|
+
height: 34px;
|
60
61
|
}
|
61
62
|
.btn-primary:hover {
|
62
|
-
color:
|
63
|
-
background-color:
|
64
|
-
background-image: -webkit-linear-gradient(
|
65
|
-
background-image: linear-gradient(
|
66
|
-
border
|
63
|
+
color: lighten($button-text-color, 20%);
|
64
|
+
background-color: lighten($button-color-1, 20%);
|
65
|
+
background-image: -webkit-linear-gradient(lighten($button-color-2, 20%), lighten($button-color-1, 20%));
|
66
|
+
background-image: linear-gradient(lighten($button-color-2, 20%), lighten($button-color-1, 20%));
|
67
|
+
border: none;
|
68
|
+
height: 34px;
|
67
69
|
}
|
68
70
|
|
69
71
|
.form-control:hover {
|
@@ -75,3 +77,7 @@ th {
|
|
75
77
|
border-color: $main-color !important;
|
76
78
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px $main-color !important;
|
77
79
|
}
|
80
|
+
|
81
|
+
.label-primary {
|
82
|
+
background-color: $main-color;
|
83
|
+
}
|
@@ -25,11 +25,13 @@ $half-spacing: 8px;
|
|
25
25
|
border-top-right-radius: 0;
|
26
26
|
}
|
27
27
|
a {
|
28
|
+
color: $text-color;
|
28
29
|
border-color: $main-color;
|
29
30
|
}
|
30
31
|
a:hover {
|
31
32
|
background-color: lighten($main-color, 20%);
|
32
33
|
border-color: lighten($main-color, 20%);
|
34
|
+
color: white;
|
33
35
|
}
|
34
36
|
a.active {
|
35
37
|
background-color: $main-color;
|
@@ -64,6 +66,9 @@ $half-spacing: 8px;
|
|
64
66
|
td {
|
65
67
|
overflow: scroll;
|
66
68
|
}
|
69
|
+
th:first-child, td:first-child {
|
70
|
+
padding-left: $spacing;
|
71
|
+
}
|
67
72
|
th:last-child {
|
68
73
|
width: 50px;
|
69
74
|
}
|
@@ -78,22 +83,19 @@ $half-spacing: 8px;
|
|
78
83
|
#dashboard-index-buttons {
|
79
84
|
display: inline-block;
|
80
85
|
margin-right: $spacing;
|
81
|
-
|
82
|
-
#new_q {
|
83
|
-
display: inline-block;
|
86
|
+
line-height: 34px;
|
84
87
|
}
|
85
88
|
|
86
|
-
|
87
|
-
|
88
|
-
.
|
89
|
-
|
90
|
-
|
91
|
-
|
89
|
+
#search-input {
|
90
|
+
position: relative;
|
91
|
+
.icon {
|
92
|
+
position: absolute;
|
93
|
+
bottom: 8px;
|
94
|
+
left: 8px;
|
95
|
+
color: #ccc;
|
92
96
|
}
|
93
|
-
|
94
|
-
|
97
|
+
input {
|
98
|
+
width: 100%;
|
99
|
+
padding-left: 30px;
|
95
100
|
}
|
96
101
|
}
|
97
|
-
.search-buttons {
|
98
|
-
display: inline-flex;
|
99
|
-
}
|
@@ -8,14 +8,20 @@ module Carload
|
|
8
8
|
|
9
9
|
before_action :set_model
|
10
10
|
before_action :set_object, only: [:edit, :update, :destroy]
|
11
|
+
before_action :transform_polymorphic_params, only: [:create, :update]
|
12
|
+
|
11
13
|
include Croppable
|
14
|
+
include ApplicationHelper
|
12
15
|
|
13
16
|
def index
|
14
17
|
authorize :carload_dashboard, :index? unless Carload.auth_solution == :none
|
15
|
-
|
16
|
-
|
18
|
+
if params[:search].present?
|
19
|
+
@query = params[:search][:query]
|
20
|
+
@objects = @model_class.search(params[:search][:query]).page(params[:page])
|
21
|
+
else
|
22
|
+
@objects = @model_class.page(params[:page])
|
23
|
+
end
|
17
24
|
@show_attributes = Dashboard.model(@model_name).index_page[:shows][:attributes] + [:created_at, :updated_at]
|
18
|
-
@search_attributes = Dashboard.model(@model_name).index_page[:searches][:attributes]
|
19
25
|
render "dashboard/#{@model_names}/index.html.erb"
|
20
26
|
end
|
21
27
|
|
@@ -82,5 +88,15 @@ module Carload
|
|
82
88
|
def rescue_unmanaged_model_error exception
|
83
89
|
redirect_to dashboard_error_path(message: exception.message)
|
84
90
|
end
|
91
|
+
|
92
|
+
def transform_polymorphic_params
|
93
|
+
polymorphic_params = {}
|
94
|
+
params[@model_name].each do |key, value|
|
95
|
+
if polymorphic? key
|
96
|
+
polymorphic_params["#{key}_id"], polymorphic_params["#{key}_type"] = value.split(',')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
params[@model_name].merge! polymorphic_params
|
100
|
+
end
|
85
101
|
end
|
86
102
|
end
|
@@ -8,8 +8,24 @@ module Carload
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
def polymorphic? attribute_name
|
12
|
+
Dashboard.model(@model_name).associated_models.each_value do |associated_model|
|
13
|
+
return associated_model[:name] if attribute_name =~ /#{associated_model[:name]}/ and associated_model[:polymorphic]
|
14
|
+
end
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
11
18
|
def image? attribute_name
|
12
19
|
attribute_name.to_s =~ /image|logo|img/
|
13
20
|
end
|
21
|
+
|
22
|
+
def id_or_ids associated_model
|
23
|
+
case associated_model[:association_type]
|
24
|
+
when :has_many
|
25
|
+
"#{associated_model[:name]}_ids"
|
26
|
+
else
|
27
|
+
"#{associated_model[:name]}_id"
|
28
|
+
end
|
29
|
+
end
|
14
30
|
end
|
15
31
|
end
|
@@ -1,59 +1,45 @@
|
|
1
1
|
module Carload
|
2
2
|
module DashboardHelper
|
3
|
-
def generate_input form, model_name, attribute_name,
|
4
|
-
if
|
3
|
+
def generate_input form, model_name, attribute_name, options = {}
|
4
|
+
if options[:polymorphic]
|
5
|
+
form.input attribute_name,
|
6
|
+
collection: @model_class.send(attribute_name.to_s.pluralize),
|
7
|
+
selected: options[:value],
|
8
|
+
input_html: { class: 'use-select2' }
|
9
|
+
elsif attribute_name =~ /_id$/
|
5
10
|
associated_model = attribute_name.gsub(/_id$/, '').to_sym
|
6
|
-
|
7
|
-
label_attribute =
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
value_method: :id,
|
16
|
-
input_html: {
|
17
|
-
class: 'use-select2',
|
18
|
-
data: {
|
19
|
-
placeholder: t('carload.placeholder.select', thing: t("activerecord.attributes.#{real_model}.#{label_attribute}"))
|
20
|
-
}
|
21
|
-
},
|
22
|
-
wrapper_html: {
|
23
|
-
id: "#{real_model.camelize}-#{label_attribute}"
|
24
|
-
}
|
25
|
-
)
|
26
|
-
end
|
27
|
-
# Add JavaScript to select which real model to work on.
|
28
|
-
forms << <<-EOT
|
29
|
-
<script>
|
30
|
-
$('.#{model_name}_#{associated_model}_id').hide()
|
31
|
-
if ($('##{model_name}_#{associated_model}_type').val() != '') {
|
32
|
-
$('#' + $('##{model_name}_#{associated_model}_type').val() + '-#{label_attribute}').show()
|
33
|
-
}
|
34
|
-
$('##{model_name}_#{associated_model}_type').change(function() {
|
35
|
-
$('.#{model_name}_#{associated_model}_id').hide()
|
36
|
-
$('#' + $(this).val() + '-#{label_attribute}').show()
|
37
|
-
$('.package_packagable_id > .select2-container').css('width', '100%')
|
38
|
-
})
|
39
|
-
</script>
|
40
|
-
EOT
|
41
|
-
raw forms.html_safe
|
42
|
-
else
|
43
|
-
form.association associated_model,
|
44
|
-
label_method: label_attribute,
|
45
|
-
label: t("activerecord.models.#{associated_model}"),
|
46
|
-
input_html: {
|
47
|
-
class: 'use-select2',
|
48
|
-
data: {
|
49
|
-
placeholder: t('carload.placeholder.select', thing: t("activerecord.attributes.#{associated_model}.#{label_attribute}"))
|
50
|
-
}
|
11
|
+
association_specs = Dashboard.model(model_name).associated_models[associated_model]
|
12
|
+
label_attribute = association_specs[:choose_by]
|
13
|
+
form.association associated_model,
|
14
|
+
label_method: label_attribute,
|
15
|
+
label: t("activerecord.models.#{associated_model}"),
|
16
|
+
input_html: {
|
17
|
+
class: 'use-select2',
|
18
|
+
data: {
|
19
|
+
placeholder: t('carload.placeholder.select', thing: t("activerecord.attributes.#{associated_model}.#{label_attribute}"))
|
51
20
|
}
|
52
|
-
|
21
|
+
}
|
22
|
+
elsif attribute_name =~ /_ids$/
|
23
|
+
# Mandle many-to-many association.
|
24
|
+
associated_model = attribute_name.gsub(/_ids$/, '').to_sym
|
25
|
+
association_specs = Dashboard.model(model_name).associated_models[associated_model]
|
26
|
+
label_attribute = association_specs[:choose_by]
|
27
|
+
form.input attribute_name,
|
28
|
+
label: t("activerecord.attributes.#{associated_model}.#{label_attribute}") + " (#{t("activerecord.models.#{associated_model}")})",
|
29
|
+
collection: associated_model.to_s.camelize.constantize.all,
|
30
|
+
label_method: label_attribute,
|
31
|
+
value_method: :id,
|
32
|
+
input_html: {
|
33
|
+
class: 'use-select2',
|
34
|
+
multiple: true,
|
35
|
+
data: {
|
36
|
+
placeholder: t('carload.placeholder.select', thing: t("activerecord.attributes.#{associated_model}.#{label_attribute}"))
|
37
|
+
}
|
38
|
+
}
|
53
39
|
elsif attribute_name =~ /_type$/
|
54
40
|
associated_model = attribute_name.gsub(/_type$/, '').to_sym
|
55
|
-
|
56
|
-
form.input attribute_name, collection:
|
41
|
+
association_specs = Dashboard.model(model_name).associated_models[associated_model]
|
42
|
+
form.input attribute_name, collection: association_specs[:instance_models].map{ |x| x.to_s.camelize },
|
57
43
|
input_html: {
|
58
44
|
class: 'use-select2',
|
59
45
|
data: {
|
@@ -67,20 +53,29 @@ module Carload
|
|
67
53
|
end
|
68
54
|
end
|
69
55
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
56
|
+
def generate_show_title attribute
|
57
|
+
case attribute
|
58
|
+
when Symbol
|
59
|
+
begin
|
60
|
+
t("activerecord.attributes.#{@model_name}.#{attribute}", raise: true)
|
61
|
+
rescue
|
62
|
+
t("carload.activerecord.#{attribute}", raise: true)
|
63
|
+
end
|
64
|
+
when String
|
65
|
+
begin
|
66
|
+
t("activerecord.attributes.#{@model_name}.#{attribute}", raise: true)
|
67
|
+
rescue
|
68
|
+
"#{t("activerecord.attributes.#{attribute}", raise: true)} (#{t("activerecord.models.#{attribute.split('.').first.to_s.singularize}", raise: true)})"
|
69
|
+
end
|
70
|
+
when Array
|
71
|
+
if attribute.first == :pluck
|
72
|
+
raise UnsupportedError.new("attribute #{attribute}") if attribute.size != 3
|
73
|
+
model_name = attribute[1].to_s.singularize
|
74
|
+
attribute_name = attribute[2]
|
75
|
+
"#{t("activerecord.attributes.#{model_name}.#{attribute_name}", raise: true)} (#{t("activerecord.models.#{model_name}", raise: true)})"
|
76
|
+
else
|
77
|
+
"#{t("activerecord.attributes.#{attribute.join('.')}", raise: true)} (#{t("activerecord.models.#{attribute[0].to_s.singularize}", raise: true)})"
|
78
|
+
end
|
84
79
|
end
|
85
80
|
end
|
86
81
|
|
@@ -89,7 +84,20 @@ module Carload
|
|
89
84
|
when Symbol
|
90
85
|
object.send attribute
|
91
86
|
when String
|
92
|
-
eval "object.#{attribute.gsub('.', '&.')}"
|
87
|
+
res = eval "object.#{attribute.gsub('.', '&.')}"
|
88
|
+
case res
|
89
|
+
when String
|
90
|
+
res
|
91
|
+
when Array
|
92
|
+
raw res.map { |x| "<span class='label label-primary'>#{x}</span>" }.join(' ')
|
93
|
+
end
|
94
|
+
when Array
|
95
|
+
if attribute.first == :pluck
|
96
|
+
raise UnsupportedError.new("attribute #{attribute}") if attribute.size != 3
|
97
|
+
generate_show object, "#{attribute[1].to_s.pluralize}.pluck(:#{attribute[2]})"
|
98
|
+
else
|
99
|
+
generate_show object, attribute.join('.')
|
100
|
+
end
|
93
101
|
end
|
94
102
|
end
|
95
103
|
end
|
@@ -1,7 +1,19 @@
|
|
1
1
|
<%= simple_form_for @object, url: "/carload/dashboard/#{@model_names}/#{@object.id}" do |f| %>
|
2
|
+
<!-- Normal attributes -->
|
2
3
|
<% @model_class.columns_hash.each do |name, column| %>
|
3
|
-
<% next if
|
4
|
-
<%= generate_input
|
4
|
+
<% next if Carload::ModelSpec::SkippedAttributes.include? name or polymorphic? name %>
|
5
|
+
<%= generate_input f, @model_name, name %>
|
6
|
+
<% end %>
|
7
|
+
<!-- Polymorphics -->
|
8
|
+
<% Dashboard.model(@model_name).associated_models.each_value do |associated_model| %>
|
9
|
+
<% next if associated_model[:polymorphic] != true %>
|
10
|
+
<%= generate_input f, @model_name, associated_model[:name], polymorphic: true,
|
11
|
+
value: "#{@object.send("#{associated_model[:name]}_id")},#{@object.send("#{associated_model[:name]}_type")}" %>
|
12
|
+
<% end %>
|
13
|
+
<!-- Join tables -->
|
14
|
+
<% Dashboard.model(@model_name).associated_models.each_value do |associated_model| %>
|
15
|
+
<% next if not associated_model[:join_table] %>
|
16
|
+
<%= generate_input f, @model_name, id_or_ids(associated_model) %>
|
5
17
|
<% end %>
|
6
18
|
<%= f.button :submit, t('carload.action.submit'), class: 'btn btn-primary' %>
|
7
19
|
<% end %>
|
@@ -9,13 +9,7 @@
|
|
9
9
|
<tr>
|
10
10
|
<th width='20'>ID</th>
|
11
11
|
<% @show_attributes.each do |attribute| %>
|
12
|
-
<th width='100'>
|
13
|
-
<% begin %>
|
14
|
-
<%= t("activerecord.attributes.#{@model_name}.#{attribute}", raise: true) %>
|
15
|
-
<% rescue %>
|
16
|
-
<%= t("carload.activerecord.#{attribute}") %>
|
17
|
-
<% end %>
|
18
|
-
</th>
|
12
|
+
<th width='100'><%= generate_show_title attribute rescue attribute %></th>
|
19
13
|
<% end %>
|
20
14
|
<th width='20'><%= t('carload.actions') %></th>
|
21
15
|
</tr>
|
@@ -1,10 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
<div class='search-buttons'>
|
8
|
-
<%= f.submit t('carload.action.search'), class: 'btn btn-primary' %>
|
9
|
-
</div>
|
10
|
-
<% end %>
|
1
|
+
<div id='search-input'>
|
2
|
+
<%= form_for :search, url: dashboard_search_path(@model_names), method: :get do |f| %>
|
3
|
+
<span class='icon'><%= fa_icon('search') %></span>
|
4
|
+
<%= f.text_field :query, class: 'form-control', placeholder: 'Search ...', value: @query %>
|
5
|
+
<% end %>
|
6
|
+
</div>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title
|
4
|
+
<title><%= Carload.page.title || 'Carload' %></title>
|
5
5
|
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'/>
|
6
6
|
<%= stylesheet_link_tag 'carload/dashboard', media: 'all' %>
|
7
7
|
<%= javascript_include_tag 'carload/dashboard' %>
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</div>
|
26
26
|
|
27
27
|
<footer class='center'>
|
28
|
-
<%= raw t('carload.footer.message') %>
|
28
|
+
<%= raw Carload.page.footer || t('carload.footer.message') %>
|
29
29
|
</footer>
|
30
30
|
</div>
|
31
31
|
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class CarloadEnableZhparserExtension < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
enable_extension :zhparser
|
4
|
+
execute 'create text search configuration zhparser (parser = zhparser);'
|
5
|
+
execute 'alter text search configuration zhparser add mapping for n,v,a,i,e,l with simple;'
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Carload
|
2
|
+
module AssociationPipelines
|
3
|
+
def association_pipelines
|
4
|
+
[ :pipeline_1, :pipeline_2, :pipeline_3 ]
|
5
|
+
end
|
6
|
+
|
7
|
+
# Find polymorphic instance models.
|
8
|
+
def pipeline_1 association
|
9
|
+
return unless association.options[:polymorphic]
|
10
|
+
associated_model = @associated_models[association.name]
|
11
|
+
ActiveRecord::Base.descendants.each do |model|
|
12
|
+
next if model.name == 'ApplicationRecord' or model.name.underscore == @name.to_s
|
13
|
+
model.reflect_on_all_associations.each do |model_association|
|
14
|
+
next unless model_association.options[:as] == association.name
|
15
|
+
associated_model[:instance_models] ||= []
|
16
|
+
associated_model[:instance_models] << model.name.underscore.to_sym
|
17
|
+
if not associated_model[:attributes]
|
18
|
+
associated_model[:attributes] = model.column_names - ModelSpec::SkippedAttributes
|
19
|
+
else
|
20
|
+
associated_model[:attributes] = associated_model[:attributes] & model.column_names
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add possible attributes to let user choose.
|
27
|
+
def pipeline_2 association
|
28
|
+
return unless associated_model = @associated_models[association.name.to_s.singularize.to_sym]
|
29
|
+
model = association.name.to_s.singularize.camelize.constantize rescue return
|
30
|
+
associated_model[:attributes] ||= []
|
31
|
+
associated_model[:attributes] = model.column_names - ModelSpec::SkippedAttributes
|
32
|
+
associated_model[:attributes] = associated_model[:attributes] - [
|
33
|
+
"#{@name}_id",
|
34
|
+
"#{associated_model[:polymorphic]}_id",
|
35
|
+
"#{associated_model[:polymorphic]}_type"
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Add has-many permitted attribute.
|
40
|
+
def pipeline_3 association
|
41
|
+
_association = (association.delegate_reflection rescue nil) || association
|
42
|
+
return unless _association.class == ActiveRecord::Reflection::HasManyReflection
|
43
|
+
# Exclude join table.
|
44
|
+
return unless @klass.reflect_on_all_associations.select { |x| x.options[:through] == _association.name }.empty?
|
45
|
+
@attributes[:permitted].each do |permitted|
|
46
|
+
next unless permitted.class == Hash
|
47
|
+
return if permitted.keys.first == :"#{_association.class_name.underscore}_ids"
|
48
|
+
end
|
49
|
+
@attributes[:permitted] << { :"#{_association.class_name.underscore}_ids" => [] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/carload/dashboard.rb
CHANGED
@@ -1,112 +1,12 @@
|
|
1
1
|
module Carload
|
2
2
|
class Dashboard
|
3
|
-
class ModelSpec
|
4
|
-
attr_accessor :default, :attributes, :index_page, :associated_models
|
5
|
-
|
6
|
-
SkippedAttributes = [
|
7
|
-
'id', 'created_at', 'updated_at',
|
8
|
-
'encrypted_password', 'reset_password_token',
|
9
|
-
'reset_password_sent_at', 'remember_created_at',
|
10
|
-
'sign_in_count', 'current_sign_in_at',
|
11
|
-
'last_sign_in_at', 'current_sign_in_ip',
|
12
|
-
'last_sign_in_ip'
|
13
|
-
].freeze
|
14
|
-
|
15
|
-
def self.foreign_key? attribute
|
16
|
-
attribute =~ /_id$/
|
17
|
-
end
|
18
|
-
|
19
|
-
def foreign_key? attribute
|
20
|
-
ModelSpec.foreign_key? attribute
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.polymorphic? model_class, attribute
|
24
|
-
return false unless foreign_key? attribute
|
25
|
-
model_class.column_names.include? "#{attribute.to_s.gsub('_id', '')}_type"
|
26
|
-
end
|
27
|
-
|
28
|
-
def polymorphic? model_class, attribute
|
29
|
-
ModelSpec.polymorphic? model_class, attribute
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize model_class = nil
|
33
|
-
@default = false
|
34
|
-
@attributes = ExtendedHash.new
|
35
|
-
@index_page = ExtendedHash.new
|
36
|
-
@index_page[:shows] = ExtendedHash.new
|
37
|
-
@index_page[:searches] = ExtendedHash.new
|
38
|
-
@associated_models = {}
|
39
|
-
if model_class
|
40
|
-
@attributes[:permitted] = model_class.column_names - SkippedAttributes
|
41
|
-
@attributes[:permitted].each do |attribute|
|
42
|
-
@index_page[:shows][:attributes] ||= []
|
43
|
-
@index_page[:searches][:attributes] ||= []
|
44
|
-
if foreign_key? attribute
|
45
|
-
associated_model = attribute.gsub('_id', '')
|
46
|
-
@associated_models[associated_model] = {
|
47
|
-
choose_by: nil, # Wait for setting.
|
48
|
-
polymorphic: polymorphic?(model_class, attribute),
|
49
|
-
model: model_class.name.underscore.to_sym
|
50
|
-
}
|
51
|
-
else
|
52
|
-
@index_page[:shows][:attributes] << attribute
|
53
|
-
@index_page[:searches][:attributes] << { name: attribute.to_sym, term: :cont }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def changed? spec
|
60
|
-
not @attributes[:permitted] == spec.attributes[:permitted] or
|
61
|
-
not @index_page[:searches][:attributes] == spec.index_page[:searches][:attributes]
|
62
|
-
end
|
63
|
-
|
64
|
-
def revise_stage_1!
|
65
|
-
# Handle polymorphic associated models if necessary.
|
66
|
-
@associated_models.each do |associated_model, options|
|
67
|
-
next if not options or not options[:polymorphic]
|
68
|
-
ActiveRecord::Base.descendants.each do |model|
|
69
|
-
next if model.name == 'ApplicationRecord'
|
70
|
-
if not model.reflect_on_all_associations.map(&:name).select { |x| x.to_s =~ /\b(#{options[:model]}|#{options[:model].to_s.pluralize})\b/ }.empty?
|
71
|
-
options[:available_models] ||= []
|
72
|
-
options[:available_models] << model.name.underscore
|
73
|
-
if not options[:common_attributes]
|
74
|
-
options[:common_attributes] = model.column_names - SkippedAttributes
|
75
|
-
else
|
76
|
-
options[:common_attributes] = options[:common_attributes] & model.column_names
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def revise_stage_2!
|
84
|
-
# Handle associated models if necessary.
|
85
|
-
@associated_models.each do |associated_model, options|
|
86
|
-
next if not options
|
87
|
-
if options[:polymorphic]
|
88
|
-
# There should be a <associated_model>_type already.
|
89
|
-
@index_page[:shows][:attributes] << "#{associated_model}.#{options[:choose_by]}"
|
90
|
-
@index_page[:searches][:attributes].each do |attribute|
|
91
|
-
next unless attribute[:name] == :"#{associated_model}_type"
|
92
|
-
attribute[:options] = options[:available_models]
|
93
|
-
end
|
94
|
-
else
|
95
|
-
@index_page[:searches][:attributes] << {
|
96
|
-
name: "#{associated_model}.#{options[:choose_by]}",
|
97
|
-
term: :cont
|
98
|
-
}
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
3
|
class << self
|
105
4
|
def model name, &block
|
106
5
|
name = name.to_sym
|
107
6
|
if block_given?
|
108
7
|
@@models ||= {}
|
109
8
|
spec = @@models[name] || ModelSpec.new
|
9
|
+
spec.name = name
|
110
10
|
yield spec
|
111
11
|
@@models[name] = spec
|
112
12
|
else
|
@@ -118,12 +18,9 @@ module Carload
|
|
118
18
|
model_a = options.keys.first
|
119
19
|
model_b = options.values.first
|
120
20
|
options.shift
|
21
|
+
options[:name] = model_b
|
121
22
|
@@models[model_a] ||= ModelSpec.new
|
122
23
|
@@models[model_a].associated_models[model_b] = options
|
123
|
-
unless options[:polymorphic]
|
124
|
-
@@models[model_b] ||= ModelSpec.new
|
125
|
-
@@models[model_b].associated_models[model_a] = nil
|
126
|
-
end
|
127
24
|
end
|
128
25
|
|
129
26
|
def models
|
@@ -153,10 +50,10 @@ module Carload
|
|
153
50
|
RUBY
|
154
51
|
default = false
|
155
52
|
next if spec.associated_models.empty?
|
156
|
-
spec.associated_models.
|
157
|
-
next
|
53
|
+
spec.associated_models.each_value do |associated_model|
|
54
|
+
next unless associated_model[:choose_by]
|
158
55
|
content << <<-RUBY
|
159
|
-
associate(#{{ name.to_sym => associated_model.to_sym }
|
56
|
+
associate(#{{ name.to_sym => associated_model[:name], choose_by: associated_model[:choose_by].to_sym }})
|
160
57
|
RUBY
|
161
58
|
end
|
162
59
|
end
|
data/lib/carload/engine.rb
CHANGED
@@ -8,5 +8,54 @@ module Carload
|
|
8
8
|
require_dependency file
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
config.after_initialize do
|
13
|
+
# Fill up associations of models.
|
14
|
+
Dashboard.models.each do |name, spec|
|
15
|
+
spec.klass = name.to_s.camelize.constantize
|
16
|
+
spec.klass.reflect_on_all_associations.each do |association|
|
17
|
+
spec.handle_association association, rescue: true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# Reopen model classes to add pg text search.
|
21
|
+
Dictionaries = {
|
22
|
+
en: 'english',
|
23
|
+
:'zh-CN' => 'zhparser'
|
24
|
+
}.freeze
|
25
|
+
Dashboard.models.each do |name, spec|
|
26
|
+
# NOTE: Only direct columns are included.
|
27
|
+
attributes = spec.index_page.searches.attributes.select { |x| x[:name].class == Symbol }.map { |x| x[:name] }
|
28
|
+
spec.klass.class_eval do
|
29
|
+
include PgSearch
|
30
|
+
pg_search_scope :search,
|
31
|
+
against: attributes,
|
32
|
+
using: {
|
33
|
+
tsearch: {
|
34
|
+
prefix: true,
|
35
|
+
negation: true,
|
36
|
+
dictionary: Dictionaries[I18n.locale]
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
# Reopen model classes to handle polymorphic association.
|
42
|
+
Dashboard.models.each do |name, spec|
|
43
|
+
spec.associated_models.values.select { |x| x[:polymorphic] == true }.each do |associated_model|
|
44
|
+
polymorphic_objects = []
|
45
|
+
associated_model[:instance_models].each do |instance_model|
|
46
|
+
Dashboard.model(instance_model).klass.all.each do |object|
|
47
|
+
polymorphic_objects << ["#{object.class} - #{object.send(associated_model[:choose_by])}", "#{object.id},#{object.class}"]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
spec.klass.class_eval do
|
51
|
+
class_eval <<-RUBY
|
52
|
+
def self.#{associated_model[:name].to_s.pluralize}
|
53
|
+
#{polymorphic_objects}
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
11
60
|
end
|
12
61
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Carload
|
2
|
+
class ModelSpec
|
3
|
+
include AssociationPipelines
|
4
|
+
|
5
|
+
attr_accessor :name, :klass, :default, :attributes, :index_page, :associated_models
|
6
|
+
|
7
|
+
SkippedAttributes = [
|
8
|
+
'id', 'created_at', 'updated_at',
|
9
|
+
'encrypted_password', 'reset_password_token',
|
10
|
+
'reset_password_sent_at', 'remember_created_at',
|
11
|
+
'sign_in_count', 'current_sign_in_at',
|
12
|
+
'last_sign_in_at', 'current_sign_in_ip',
|
13
|
+
'last_sign_in_ip'
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
AssociationTypes = {
|
17
|
+
ActiveRecord::Reflection::BelongsToReflection => :belongs_to,
|
18
|
+
ActiveRecord::Reflection::HasOneReflection => :has_one,
|
19
|
+
ActiveRecord::Reflection::HasManyReflection => :has_many,
|
20
|
+
ActiveRecord::Reflection::ThroughReflection => :through
|
21
|
+
}
|
22
|
+
|
23
|
+
def initialize model_class = nil
|
24
|
+
@default = false
|
25
|
+
@attributes = ExtendedHash.new
|
26
|
+
@index_page = ExtendedHash.new
|
27
|
+
@index_page[:shows] = ExtendedHash.new
|
28
|
+
@index_page[:shows][:attributes] ||= []
|
29
|
+
@index_page[:searches] = ExtendedHash.new
|
30
|
+
@index_page[:searches][:attributes] ||= []
|
31
|
+
@associated_models = {}
|
32
|
+
if model_class
|
33
|
+
@name = model_class.name.underscore
|
34
|
+
@klass = model_class
|
35
|
+
@attributes[:permitted] = (model_class.column_names - SkippedAttributes).map(&:to_sym)
|
36
|
+
# Handle model associations.
|
37
|
+
model_class.reflect_on_all_associations.each do |association|
|
38
|
+
handle_association association
|
39
|
+
end
|
40
|
+
@attributes[:permitted].each do |attribute|
|
41
|
+
next if attribute.class == Hash
|
42
|
+
@index_page[:shows][:attributes] << attribute
|
43
|
+
@index_page[:searches][:attributes] << { name: attribute.to_sym, term: :cont }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def changed? spec
|
49
|
+
not @default == spec.default or
|
50
|
+
not @attributes[:permitted] == spec.attributes[:permitted] or
|
51
|
+
not @index_page[:shows][:attributes] == spec.index_page[:shows][:attributes] or
|
52
|
+
not @index_page[:searches][:attributes] == spec.index_page[:searches][:attributes]
|
53
|
+
end
|
54
|
+
|
55
|
+
def revise!
|
56
|
+
# Handle associated models if necessary.
|
57
|
+
@associated_models.each_value do |associated_model|
|
58
|
+
next unless associated_model[:choose_by]
|
59
|
+
if associated_model[:association_type] == :has_many
|
60
|
+
show_name = [:pluck, associated_model[:name].to_s.pluralize.to_sym, associated_model[:choose_by]]
|
61
|
+
else
|
62
|
+
show_name = "#{associated_model[:name]}.#{associated_model[:choose_by]}"
|
63
|
+
end
|
64
|
+
@index_page[:shows][:attributes].delete_if { |x| x == :"#{associated_model[:name]}_id" }
|
65
|
+
@index_page[:shows][:attributes] << show_name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_association association, options = {}
|
70
|
+
begin
|
71
|
+
_association = (association.delegate_reflection rescue nil) || association
|
72
|
+
name = (_association.klass.name.underscore.to_sym rescue nil) || _association.name
|
73
|
+
association_type = AssociationTypes[_association.class]
|
74
|
+
polymorphic = association.options[:polymorphic] || association.options[:as]
|
75
|
+
foreign_key = @klass.column_names.include?("#{(_association.klass.name.underscore rescue nil) || _association.name}_id")
|
76
|
+
join_table = association.options[:through].to_s.singularize.to_sym if association.options[:through]
|
77
|
+
@associated_models[name] = {
|
78
|
+
name: name,
|
79
|
+
association_type: association_type,
|
80
|
+
polymorphic: polymorphic,
|
81
|
+
foreign_key: foreign_key,
|
82
|
+
join_table: join_table,
|
83
|
+
choose_by: nil
|
84
|
+
}.merge @associated_models[name] || {}
|
85
|
+
association_pipelines.each { |pipeline| send pipeline, association }
|
86
|
+
# Delete join-table model!
|
87
|
+
if association.options[:through]
|
88
|
+
@associated_models.delete association.options[:through]
|
89
|
+
@associated_models.delete association.options[:through].to_s.singularize.to_sym
|
90
|
+
end
|
91
|
+
rescue => e
|
92
|
+
raise e unless options[:rescue]
|
93
|
+
raise e if not e&.original_exception&.class == PG::UndefinedTable and
|
94
|
+
not e.class == ActiveRecord::NoDatabaseError
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/carload/version.rb
CHANGED
data/lib/carload.rb
CHANGED
@@ -4,13 +4,17 @@ Gem.loaded_specs['carload'].dependencies.each do |dependency|
|
|
4
4
|
end
|
5
5
|
|
6
6
|
require 'carload/extended_hash'
|
7
|
+
require 'carload/association_pipelines'
|
8
|
+
require 'carload/model_spec'
|
7
9
|
require 'carload/dashboard'
|
8
10
|
require 'carload/engine'
|
9
11
|
require 'carload/exceptions'
|
10
12
|
|
11
13
|
module Carload
|
12
14
|
def self.setup &block
|
15
|
+
# Read in configuration.
|
13
16
|
@@config = ExtendedHash.new
|
17
|
+
@@config[:page] = ExtendedHash.new
|
14
18
|
@@config[:dashboard] = ExtendedHash.new
|
15
19
|
@@config[:dashboard][:permits_user] = ExtendedHash.new
|
16
20
|
yield @@config
|
@@ -20,7 +24,7 @@ module Carload
|
|
20
24
|
if not [:carrierwave].include? @@config[:upload_solution]
|
21
25
|
raise UnsupportedError.new("upload solution #{@@config[:upload_solution]}")
|
22
26
|
end
|
23
|
-
|
27
|
+
# Define configuation helpers.
|
24
28
|
@@config.each do |key, value|
|
25
29
|
define_singleton_method key do
|
26
30
|
value
|
@@ -8,34 +8,35 @@ module Carload
|
|
8
8
|
model_specs = {}
|
9
9
|
Rails.application.eager_load! # It is necessary to load models manually.
|
10
10
|
ActiveRecord::Base.descendants.each do |model| # Rails 5 can use ApplicationRecord.
|
11
|
-
next if model.name == 'ApplicationRecord'
|
11
|
+
next if model.name == 'ApplicationRecord' or model.name == 'PgSearch::Document'
|
12
12
|
name = model.name.underscore
|
13
|
-
model_specs[name] =
|
13
|
+
model_specs[name] = ModelSpec.new model
|
14
14
|
end
|
15
15
|
spec = model_specs[model]
|
16
16
|
if not spec.associated_models.empty?
|
17
|
-
spec.revise_stage_1!
|
18
17
|
cli = HighLine.new
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
attributes.
|
25
|
-
|
26
|
-
|
18
|
+
spec.associated_models.each_value do |associated_model|
|
19
|
+
next if associated_model[:attributes].empty?
|
20
|
+
if associated_model[:polymorphic]
|
21
|
+
attributes = associated_model[:attributes]
|
22
|
+
else
|
23
|
+
attributes = model_specs[associated_model[:name].to_s].attributes.permitted.select { |x| x.class != Hash }
|
24
|
+
end
|
25
|
+
if attributes.size == 1
|
26
|
+
associated_model[:choose_by] = attributes.first
|
27
|
+
else
|
28
|
+
associated_model[:choose_by] = cli.choose do |menu|
|
29
|
+
menu.prompt = "Choose the attribute of model #{associated_model[:name]} for choosing in #{model}? "
|
30
|
+
attributes.each do |attribute|
|
31
|
+
next if attribute.to_s =~ /_id$/
|
32
|
+
menu.choice attribute
|
33
|
+
end
|
27
34
|
end
|
28
35
|
end
|
29
36
|
end
|
30
|
-
spec.
|
37
|
+
spec.revise!
|
31
38
|
end
|
32
39
|
# Check if model exists in dashboard file, but it may be changed.
|
33
|
-
begin
|
34
|
-
load 'app/carload/dashboard.rb'
|
35
|
-
rescue LoadError
|
36
|
-
Dashboard.models[model.to_sym] = spec
|
37
|
-
Dashboard.write 'app/carload/dashboard.rb'
|
38
|
-
end
|
39
40
|
if not Dashboard.models.keys.include? model.to_sym or Dashboard.model(model).changed? spec
|
40
41
|
Dashboard.models[model.to_sym] = spec
|
41
42
|
Dashboard.write 'app/carload/dashboard.rb'
|
@@ -26,5 +26,15 @@ require 'carload'
|
|
26
26
|
def copy_dashboard_file
|
27
27
|
copy_file 'dashboard.rb', 'app/carload/dashboard.rb'
|
28
28
|
end
|
29
|
+
|
30
|
+
def copy_migration_files
|
31
|
+
# Copy migrations if necessary.
|
32
|
+
case I18n.locale
|
33
|
+
when :'zh-CN'
|
34
|
+
['20161030074822_carload_enable_zhparser_extension.rb'].each do |file|
|
35
|
+
copy_file "#{Carload::Engine.root}/db/migrate/#{file}", "db/migrate/#{file}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
@@ -1,8 +1,20 @@
|
|
1
1
|
Carload.setup do |config|
|
2
|
-
#
|
2
|
+
# Set the title that will be displayed on the browser tab area.
|
3
|
+
config.page.title = nil
|
4
|
+
|
5
|
+
# Set the footer text that will be displayed on each page.
|
6
|
+
config.page.footer = nil
|
7
|
+
|
8
|
+
# Set the colors of page elements.
|
9
|
+
config.page.main_color = nil
|
10
|
+
config.page.text_color = 'black'
|
11
|
+
config.page.button_color = nil
|
12
|
+
config.page.button_text_color = nil
|
13
|
+
|
14
|
+
# Set which authentication solution is used. Currently, we only support Devise.
|
3
15
|
config.auth_solution = :devise
|
4
16
|
|
5
|
-
#
|
17
|
+
# Set which file upload solution is used. Currently, we only support Carrierwave.
|
6
18
|
config.upload_solution = :carrierwave
|
7
19
|
|
8
20
|
# Set the actions used to discern user's permission to access dashboard.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carload
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Li Dong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -129,19 +129,19 @@ dependencies:
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '3.3'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
132
|
+
name: pg_search
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - "~>"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: '1.
|
137
|
+
version: '1.0'
|
138
138
|
type: :runtime
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: '1.
|
144
|
+
version: '1.0'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: kaminari
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -227,7 +227,7 @@ files:
|
|
227
227
|
- app/assets/javascripts/carload/dashboard.js
|
228
228
|
- app/assets/stylesheets/carload/_select2.scss
|
229
229
|
- app/assets/stylesheets/carload/application.scss
|
230
|
-
- app/assets/stylesheets/carload/colors.scss
|
230
|
+
- app/assets/stylesheets/carload/colors.scss.erb
|
231
231
|
- app/assets/stylesheets/carload/common.scss
|
232
232
|
- app/assets/stylesheets/carload/dashboard.scss
|
233
233
|
- app/assets/stylesheets/carload/error.scss
|
@@ -264,11 +264,14 @@ files:
|
|
264
264
|
- config/locales/simple_form.en.yml
|
265
265
|
- config/locales/zh-CN.yml
|
266
266
|
- config/routes.rb
|
267
|
+
- db/migrate/20161030074822_carload_enable_zhparser_extension.rb
|
267
268
|
- lib/carload.rb
|
269
|
+
- lib/carload/association_pipelines.rb
|
268
270
|
- lib/carload/dashboard.rb
|
269
271
|
- lib/carload/engine.rb
|
270
272
|
- lib/carload/exceptions.rb
|
271
273
|
- lib/carload/extended_hash.rb
|
274
|
+
- lib/carload/model_spec.rb
|
272
275
|
- lib/carload/version.rb
|
273
276
|
- lib/generators/carload/USAGE
|
274
277
|
- lib/generators/carload/dash_generator.rb
|