dry_crud 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +25 -10
- data/Rakefile +30 -8
- data/VERSION +1 -1
- data/lib/generators/dry_crud/dry_crud_generator.rb +15 -2
- data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +18 -10
- data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +14 -11
- data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +71 -29
- data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +40 -3
- data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +8 -27
- data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +13 -6
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +4 -4
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.haml +5 -5
- data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +433 -0
- data/lib/generators/dry_crud/templates/spec/helpers/crud_helper_spec.rb +146 -0
- data/lib/generators/dry_crud/templates/spec/helpers/list_helper_spec.rb +154 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_form_builder_spec.rb +215 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_helper_spec.rb +387 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_table_builder_spec.rb +120 -0
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +244 -0
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +160 -0
- data/lib/generators/dry_crud/templates/test/crud_test_model.rb +45 -18
- data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +19 -9
- data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +11 -14
- data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +26 -13
- data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +0 -4
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +6 -0
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +9 -35
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +5 -4
- data/test/templates/Gemfile +3 -1
- data/test/templates/app/controllers/people_controller.rb +1 -1
- data/test/templates/app/controllers/vips_controller.rb +1 -1
- data/test/templates/app/models/city.rb +1 -1
- data/test/templates/app/views/admin/cities/_form.html.erb +1 -1
- data/test/templates/app/views/admin/cities/_form.html.haml +1 -1
- data/test/templates/app/views/admin/countries/_list.html.erb +3 -4
- data/test/templates/app/views/admin/countries/_list.html.haml +3 -4
- data/test/templates/app/views/ajax/_form.html.erb +1 -1
- data/test/templates/app/views/ajax/_form.html.haml +1 -1
- data/test/templates/spec/controllers/admin/cities_controller_spec.rb +74 -0
- data/test/templates/spec/controllers/admin/countries_controller_spec.rb +56 -0
- data/test/templates/spec/controllers/people_controller_spec.rb +80 -0
- data/test/templates/spec/routing/cities_routing_spec.rb +11 -0
- data/test/templates/spec/routing/countries_routing_spec.rb +11 -0
- data/test/templates/test/functional/admin/cities_controller_test.rb +1 -1
- data/test/templates/test/functional/admin/countries_controller_test.rb +1 -1
- data/test/templates/test/functional/people_controller_test.rb +3 -3
- metadata +18 -7
data/README.rdoc
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
= DRY CRUD
|
2
2
|
|
3
|
+
{<img src="https://secure.travis-ci.org/codez/dry_crud.png" />}[http://travis-ci.org/codez/dry_crud]
|
4
|
+
|
3
5
|
DRY CRUD generates simple and extendable controller, views and helpers that support you to DRY up the CRUD code in your Rails project. Start with these elements and build a clean base to efficiently develop your application upon.
|
4
6
|
|
5
7
|
Create your Rails application directly with the DRY CRUD application template:
|
6
8
|
|
7
|
-
rails new
|
9
|
+
rails new APP_NAME -m https://raw.github.com/codez/dry_crud/master/template.rb
|
8
10
|
|
9
11
|
If your application already exists or you prefer the DIY way, then install the Gem (<tt>gem install dry_crud</tt>), add it to your Gemfile and run the generator. You may remove the Gemfile entry again afterwards, it is not required anymore.
|
10
12
|
|
11
|
-
rails generate dry_crud
|
13
|
+
rails generate dry_crud [--templates haml] [--tests rspec]
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
rails generate dry_crud -t haml
|
15
|
+
By default, DRY CRUD generates ERB templates and Test::Unit tests. Pass the options above to generate HAML templates and/or RSpec examples instead.
|
16
16
|
|
17
17
|
To integrate DRY CRUD into your code, only a few additions are required:
|
18
18
|
|
@@ -162,10 +162,10 @@ To render custom columns, use the :col method:
|
|
162
162
|
|
163
163
|
Forms work very similar. In the most simple case, you just have to specify which attributes of a model to create input fields for, and you get a complete form with error messages, labeled input fields according the column types and a save button:
|
164
164
|
|
165
|
-
<%=
|
165
|
+
<%= crud_form(@person, :firstname, :lastname, :age, :city) -%>
|
166
166
|
|
167
167
|
Of course, custom input fields may be defined as well:
|
168
|
-
<%=
|
168
|
+
<%= crud_form(@person, :url => custom_update_person_path(@person.id)) do |f| %>
|
169
169
|
<%= f.labeled_input_fields :firstname, :lastname %>
|
170
170
|
<%= f.labeled(:sex) do %>
|
171
171
|
<%= f.radio_button :sex, true %> female
|
@@ -286,7 +286,9 @@ views/shared/_error_messages.html.erb:: Partial to display the validation errors
|
|
286
286
|
|
287
287
|
views/layouts/crud.html.erb:: An example layout showing how to use the <tt>@title</tt> and +flash+. Most probably you want to merge this with your <tt>application.html.erb</tt> or adapt the main CRUD templates, so you wont need this file.
|
288
288
|
|
289
|
-
views/layouts/
|
289
|
+
views/layouts/_flash.html.erb:: An simple partial to display the various flash messages. Included from <tt>crud.html.erb</tt>.
|
290
|
+
|
291
|
+
views/layouts/_nav.html.erb:: An empty file to put your navigation into. Included from <tt>crud.html.erb</tt>.
|
290
292
|
|
291
293
|
app/assets/stylesheets/crud.scss:: A simple SCSS with all the classes and ids used in the CRUD code.
|
292
294
|
|
@@ -299,9 +301,22 @@ app/assets/images/action/*.png:: Some sample action icons from the {Open Icon Li
|
|
299
301
|
|
300
302
|
{test/custom_assertions.rb}[http://codez.ch/dry_crud/CustomAssertions.html]:: A handful of convenient assertions. Include this module into your <tt>test_helper.rb</tt> file.
|
301
303
|
|
302
|
-
{test/
|
304
|
+
{test/functional/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/CrudControllerTestHelper.html]:: A module to include into the functional tests for your +CrudController+ subclasses. Contains a handful of CRUD functionality tests for the provided implementation. So for each new CRUD controller, you get 20 tests for free.
|
305
|
+
|
306
|
+
test/functional/crud_test_models_controller_test.rb:: Functional tests for the basic +CrudController+ functionality.
|
303
307
|
|
304
308
|
test/several other tests:: Testing the provided implementation and a great base to test your adaptions of the CRUD code.
|
305
309
|
|
306
310
|
|
307
|
-
|
311
|
+
=== Specs:
|
312
|
+
|
313
|
+
spec/support/crud_controller_examples.rb:: A whole set of shared exampled to include into your controller specs. See <tt>spec/controllers/crud_test_models_controller_spec.rb</tt> for usage. So for each new CRUD controller, you get all the basic specs for free.
|
314
|
+
|
315
|
+
spec/support/crud_controller_test_helper.rb:: Convenience methods used by the crud controller examples.
|
316
|
+
|
317
|
+
{spec/support/crud_test_model.rb}[http://codez.ch/dry_crud/CrudTestHelper.html]:: A dummy model to run CRUD tests against.
|
318
|
+
|
319
|
+
spec/controllers/crud_test_models_controller_spec.rb:: Controller specs to test the basic +CrudController+ functionality.
|
320
|
+
|
321
|
+
spec/helpers/*_spec.rb:: The specs for all the helpers included in DRY CRUD.
|
322
|
+
|
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake/testtask'
|
3
|
+
require 'rspec/core/rake_task'
|
3
4
|
require 'rubygems/package_task'
|
4
5
|
require 'rdoc/task'
|
5
6
|
|
@@ -11,15 +12,25 @@ GENERATOR_ROOT = File.join(File.dirname(__FILE__), 'lib', 'generators', 'dry_cru
|
|
11
12
|
task :default => :test
|
12
13
|
|
13
14
|
desc "Run all tests"
|
14
|
-
task :test => ['test:
|
15
|
-
|
15
|
+
task :test => ['test:unit', 'test:spec']
|
16
|
+
|
17
|
+
|
18
|
+
namespace :test do
|
19
|
+
|
20
|
+
desc "Run Test::Unit tests"
|
21
|
+
Rake::TestTask.new(:unit => 'test:app:init') do |test|
|
16
22
|
test.libs << "test/test_app/test"
|
17
23
|
test.test_files = Dir[ "test/test_app/test/**/*_test.rb" ]
|
18
24
|
test.verbose = true
|
19
25
|
end
|
20
|
-
|
26
|
+
|
27
|
+
desc "Run RSpec tests"
|
28
|
+
RSpec::Core::RakeTask.new(:spec => 'test:app:init') do |t|
|
29
|
+
t.ruby_opts = "-I test/test_app/spec"
|
30
|
+
t.pattern = "test/test_app/spec/**/*_spec.rb"
|
31
|
+
end
|
32
|
+
|
21
33
|
|
22
|
-
namespace :test do
|
23
34
|
namespace :app do
|
24
35
|
task :environment do
|
25
36
|
ENV['RAILS_ROOT'] = TEST_APP_ROOT
|
@@ -33,7 +44,8 @@ namespace :test do
|
|
33
44
|
unless File.exist?(TEST_APP_ROOT)
|
34
45
|
sh "rails new #{TEST_APP_ROOT} --skip-bundle"
|
35
46
|
FileUtils.cp(File.join(File.dirname(__FILE__), 'test', 'templates', 'Gemfile'), TEST_APP_ROOT)
|
36
|
-
sh "cd #{TEST_APP_ROOT}; bundle install" # update Gemfile.lock
|
47
|
+
sh "cd #{TEST_APP_ROOT}; bundle install --local" # update Gemfile.lock
|
48
|
+
sh "cd #{TEST_APP_ROOT}; rails g rspec:install"
|
37
49
|
FileUtils.rm_f(File.join(TEST_APP_ROOT, 'test', 'performance', 'browsing_test.rb'))
|
38
50
|
end
|
39
51
|
end
|
@@ -42,7 +54,10 @@ namespace :test do
|
|
42
54
|
task :generate_crud => [:create, :environment] do
|
43
55
|
require File.join(GENERATOR_ROOT, 'dry_crud_generator')
|
44
56
|
|
45
|
-
DryCrudGenerator.new(
|
57
|
+
DryCrudGenerator.new([], {:force => true,
|
58
|
+
:templates => ENV['HAML'] ? 'haml' : 'erb',
|
59
|
+
:tests => 'all'},
|
60
|
+
:destination_root => TEST_APP_ROOT).invoke_all
|
46
61
|
end
|
47
62
|
|
48
63
|
desc "Populates the test application with some models and controllers"
|
@@ -50,6 +65,10 @@ namespace :test do
|
|
50
65
|
# copy test app templates
|
51
66
|
FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', 'templates', '.'), TEST_APP_ROOT)
|
52
67
|
|
68
|
+
# copy shared fixtures
|
69
|
+
FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', 'templates', 'test', 'fixtures'),
|
70
|
+
File.join(TEST_APP_ROOT, 'spec'))
|
71
|
+
|
53
72
|
# replace some unused files
|
54
73
|
FileUtils.rm_f(File.join(TEST_APP_ROOT, 'public', 'index.html'))
|
55
74
|
layouts = File.join(TEST_APP_ROOT, 'app', 'views', 'layouts')
|
@@ -65,7 +84,10 @@ namespace :test do
|
|
65
84
|
Dir.glob(File.join(TEST_APP_ROOT, 'app', 'views', '**', "*.#{exclude}")).each do |f|
|
66
85
|
FileUtils.rm(f)
|
67
86
|
end
|
68
|
-
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "Insert seed data into the test database"
|
90
|
+
task :seed => :populate do
|
69
91
|
# migrate the database
|
70
92
|
FileUtils.cd(TEST_APP_ROOT) do
|
71
93
|
sh "rake db:migrate db:seed RAILS_ENV=development --trace"
|
@@ -74,7 +96,7 @@ namespace :test do
|
|
74
96
|
end
|
75
97
|
|
76
98
|
desc "Initializes the test application with a couple of classes"
|
77
|
-
task :init => [:
|
99
|
+
task :init => [:seed,
|
78
100
|
:customize]
|
79
101
|
|
80
102
|
desc "Customize some of the functionality provided by dry_crud"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0
|
@@ -3,6 +3,7 @@ require 'rails/generators'
|
|
3
3
|
class DryCrudGenerator < Rails::Generators::Base
|
4
4
|
|
5
5
|
class_options %w(templates -t) => 'erb'
|
6
|
+
class_options %w(tests) => 'testunit'
|
6
7
|
|
7
8
|
|
8
9
|
def self.source_root
|
@@ -11,16 +12,28 @@ class DryCrudGenerator < Rails::Generators::Base
|
|
11
12
|
|
12
13
|
def install_dry_crud
|
13
14
|
# copy everything in template subfolders
|
14
|
-
|
15
|
+
exclude_template = options[:templates].downcase == 'haml' ? '.erb' : '.haml'
|
16
|
+
|
17
|
+
exclude_test_dir = case options[:tests].downcase
|
18
|
+
when 'rspec' then 'test'
|
19
|
+
when 'all' then 'exclude_nothing'
|
20
|
+
else 'spec'
|
21
|
+
end
|
15
22
|
|
16
23
|
Dir.chdir(self.class.source_root) do
|
17
24
|
Dir.glob(File.join('**', '**')).sort.each do |file_source|
|
18
25
|
if !File.directory?(file_source) &&
|
19
|
-
!file_source.end_with?(
|
26
|
+
!file_source.end_with?(exclude_template) &&
|
27
|
+
!file_source.start_with?(exclude_test_dir) &&
|
20
28
|
file_source != 'INSTALL'
|
21
29
|
copy_file(file_source)
|
22
30
|
end
|
23
31
|
end
|
32
|
+
|
33
|
+
unless exclude_test_dir == 'spec'
|
34
|
+
copy_file(File.join('test', 'crud_test_model.rb'),
|
35
|
+
File.join('spec', 'support', 'crud_test_model.rb'))
|
36
|
+
end
|
24
37
|
end
|
25
38
|
|
26
39
|
readme "INSTALL"
|
@@ -48,12 +48,13 @@ class CrudController < ListController
|
|
48
48
|
# There are before and after create callbacks to hook into the action.
|
49
49
|
# To customize the response, you may overwrite this action and call
|
50
50
|
# super with a block that gets the format parameter.
|
51
|
+
# Specify a :location option if you wish to do a custom redirect.
|
51
52
|
# POST /entries
|
52
53
|
# POST /entries.json
|
53
|
-
def create(&block)
|
54
|
+
def create(options = {}, &block)
|
54
55
|
assign_attributes
|
55
56
|
created = with_callbacks(:create, :save) { entry.save }
|
56
|
-
respond_with(entry, :success => created, &block)
|
57
|
+
respond_with(entry, options.reverse_merge(:success => created), &block)
|
57
58
|
end
|
58
59
|
|
59
60
|
# Display a form to edit an exisiting entry of this model.
|
@@ -66,28 +67,30 @@ class CrudController < ListController
|
|
66
67
|
# There are before and after update callbacks to hook into the action.
|
67
68
|
# To customize the response, you may overwrite this action and call
|
68
69
|
# super with a block that gets the format parameter.
|
70
|
+
# Specify a :location option if you wish to do a custom redirect.
|
69
71
|
# PUT /entries/1
|
70
72
|
# PUT /entries/1.json
|
71
|
-
def update(&block)
|
73
|
+
def update(options = {}, &block)
|
72
74
|
assign_attributes
|
73
75
|
updated = with_callbacks(:update, :save) { entry.save }
|
74
|
-
respond_with(entry, :success => updated, &block)
|
76
|
+
respond_with(entry, options.reverse_merge(:success => updated), &block)
|
75
77
|
end
|
76
78
|
|
77
79
|
# Destroy an existing entry of this model.
|
78
80
|
# There are before and after destroy callbacks to hook into the action.
|
79
81
|
# To customize the response, you may overwrite this action and call
|
80
82
|
# super with a block that gets success and format parameters.
|
83
|
+
# Specify a :location option if you wish to do a custom redirect.
|
81
84
|
# DELETE /entries/1
|
82
85
|
# DELETE /entries/1.json
|
83
|
-
def destroy(&block)
|
86
|
+
def destroy(options = {}, &block)
|
84
87
|
destroyed = run_callbacks(:destroy) { entry.destroy }
|
85
88
|
flash[:alert] ||= error_messages.presence || flash_message(:failure) if !destroyed && request.format == :html
|
86
89
|
location = !destroyed && request.env["HTTP_REFERER"].presence || index_url
|
87
|
-
respond_with(entry, :success => destroyed, :location => location, &block)
|
90
|
+
respond_with(entry, options.reverse_merge(:success => destroyed, :location => location), &block)
|
88
91
|
end
|
89
92
|
|
90
|
-
|
93
|
+
private
|
91
94
|
|
92
95
|
############# CUSTOMIZABLE HELPER METHODS ##############################
|
93
96
|
|
@@ -108,7 +111,7 @@ class CrudController < ListController
|
|
108
111
|
|
109
112
|
# Assigns the attributes from the params to the model entry.
|
110
113
|
def assign_attributes
|
111
|
-
entry.attributes =
|
114
|
+
entry.attributes = model_params
|
112
115
|
end
|
113
116
|
|
114
117
|
# A label for the current entry, including the model name.
|
@@ -144,13 +147,18 @@ class CrudController < ListController
|
|
144
147
|
def error_messages
|
145
148
|
@@helper.safe_join(entry.errors.full_messages, '<br/>'.html_safe)
|
146
149
|
end
|
150
|
+
|
151
|
+
# The form params for this model.
|
152
|
+
def model_params
|
153
|
+
params[model_identifier]
|
154
|
+
end
|
147
155
|
|
148
156
|
|
149
157
|
class << self
|
150
158
|
# The identifier of the model used for form parameters.
|
151
159
|
# I.e., the symbol of the underscored model name.
|
152
160
|
def model_identifier
|
153
|
-
@model_identifier ||= model_class.
|
161
|
+
@model_identifier ||= model_class.model_name.param_key
|
154
162
|
end
|
155
163
|
|
156
164
|
# Convenience callback to apply a callback on both form actions (new and edit).
|
@@ -168,7 +176,7 @@ class CrudController < ListController
|
|
168
176
|
super(controller, with_path_args(resources, controller), options)
|
169
177
|
end
|
170
178
|
|
171
|
-
|
179
|
+
private
|
172
180
|
|
173
181
|
# Check whether the resource has errors. Additionally checks the :success option.
|
174
182
|
def has_errors?
|
@@ -23,7 +23,7 @@ class ListController < ApplicationController
|
|
23
23
|
respond_with(entries, &block)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
private
|
27
27
|
|
28
28
|
# Helper method to access the entries to be displayed in the current index page in an uniform way.
|
29
29
|
def entries
|
@@ -52,7 +52,7 @@ class ListController < ApplicationController
|
|
52
52
|
# Get the instance variable named after the model_class.
|
53
53
|
# If the collection variable is required, pass true as the second argument.
|
54
54
|
def get_model_ivar(plural = false)
|
55
|
-
name = model_class
|
55
|
+
name = ivar_name(model_class)
|
56
56
|
name = name.pluralize if plural
|
57
57
|
instance_variable_get(:"@#{name}")
|
58
58
|
end
|
@@ -61,13 +61,17 @@ class ListController < ApplicationController
|
|
61
61
|
# If the value is a collection, sets the plural name.
|
62
62
|
def set_model_ivar(value)
|
63
63
|
name = if value.respond_to?(:klass) # ActiveRecord::Relation
|
64
|
-
value.klass.
|
64
|
+
ivar_name(value.klass).pluralize
|
65
65
|
elsif value.respond_to?(:each) # Array
|
66
|
-
value.first.klass.
|
66
|
+
ivar_name(value.first.klass).pluralize
|
67
67
|
else
|
68
|
-
value.class
|
68
|
+
ivar_name(value.class)
|
69
69
|
end
|
70
|
-
instance_variable_set(:"@#{name
|
70
|
+
instance_variable_set(:"@#{name}", value)
|
71
|
+
end
|
72
|
+
|
73
|
+
def ivar_name(klass)
|
74
|
+
klass.model_name.param_key
|
71
75
|
end
|
72
76
|
|
73
77
|
class << self
|
@@ -102,14 +106,13 @@ class ListController < ApplicationController
|
|
102
106
|
# If a callback renders or redirects, the action is not rendered.
|
103
107
|
def render_with_callbacks(*args, &block)
|
104
108
|
options = _normalize_render(*args, &block)
|
105
|
-
p options if options[:location] == :back
|
106
109
|
callback = "render_#{options[:template]}"
|
107
110
|
run_callbacks(callback) if respond_to?(:"_run_#{callback}_callbacks", true)
|
108
111
|
|
109
112
|
render_without_callbacks(*args, &block) unless performed?
|
110
113
|
end
|
111
114
|
|
112
|
-
|
115
|
+
private
|
113
116
|
|
114
117
|
# Helper method the run the given block in between the before and after
|
115
118
|
# callbacks of the given kinds.
|
@@ -145,7 +148,7 @@ class ListController < ApplicationController
|
|
145
148
|
controller.alias_method_chain :list_entries, :search
|
146
149
|
end
|
147
150
|
|
148
|
-
|
151
|
+
private
|
149
152
|
|
150
153
|
# Enhance the list entries with an optional search criteria
|
151
154
|
def list_entries_with_search
|
@@ -192,7 +195,7 @@ class ListController < ApplicationController
|
|
192
195
|
controller.alias_method_chain :list_entries, :sort
|
193
196
|
end
|
194
197
|
|
195
|
-
|
198
|
+
private
|
196
199
|
|
197
200
|
# Enhance the list entries with an optional sort order.
|
198
201
|
def list_entries_with_sort
|
@@ -302,7 +305,7 @@ class ListController < ApplicationController
|
|
302
305
|
controller.alias_method_chain :path_args, :nesting
|
303
306
|
end
|
304
307
|
|
305
|
-
|
308
|
+
private
|
306
309
|
|
307
310
|
# Returns the direct parent ActiveRecord of the current request, if any.
|
308
311
|
def parent
|
@@ -3,40 +3,76 @@
|
|
3
3
|
# is included in CrudController.
|
4
4
|
module CrudHelper
|
5
5
|
|
6
|
-
# Renders a
|
7
|
-
# given attribute array
|
8
|
-
# may be given as the last argument.
|
6
|
+
# Renders a crud form for the current entry with default_attrs or the
|
7
|
+
# given attribute array. An options hash may be given as the last argument.
|
9
8
|
# If a block is given, a custom form may be rendered and attrs is ignored.
|
10
|
-
def
|
11
|
-
|
12
|
-
|
9
|
+
def entry_form(*attrs, &block)
|
10
|
+
options = attrs.extract_options!
|
11
|
+
attrs = default_attrs - [:created_at, :updated_at] if attrs.blank?
|
12
|
+
attrs << options
|
13
|
+
crud_form(path_args(entry), *attrs, &block)
|
13
14
|
end
|
14
15
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
# Renders a standard form for the given entry and attributes.
|
17
|
+
# The form is rendered with a basic save and cancel button.
|
18
|
+
# If a block is given, custom input fields may be rendered and attrs is ignored.
|
19
|
+
# An options hash may be given as the last argument.
|
20
|
+
def crud_form(object, *attrs, &block)
|
21
|
+
options = attrs.extract_options!
|
22
|
+
cancel_url = get_cancel_url(object, options)
|
23
|
+
|
24
|
+
standard_form(object, options) do |form|
|
25
|
+
content = if block_given?
|
26
|
+
capture(form, &block)
|
27
|
+
else
|
28
|
+
form.labeled_input_fields(*attrs)
|
25
29
|
end
|
30
|
+
|
31
|
+
content << form.standard_actions(cancel_url)
|
32
|
+
content.html_safe
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a table of the current entries with the default or the passed
|
37
|
+
# attributes in its columns.
|
38
|
+
# If attrs are present, the first column will link to the show
|
39
|
+
# action. Edit and destroy actions are appended to the end of each row.
|
40
|
+
# If a block is given, the column defined there will be inserted
|
41
|
+
# between the given attributes and the actions.
|
42
|
+
# An options hash for the table builder may be given as the last argument.
|
43
|
+
def crud_table(*attrs, &block)
|
44
|
+
options = attrs.extract_options!
|
45
|
+
attributes = (block_given? || attrs.present?) ? attrs : default_attrs
|
46
|
+
first = attributes.shift
|
47
|
+
table(entries, options) do |t|
|
48
|
+
col_show(t, first) if first
|
49
|
+
t.sortable_attrs(*attributes)
|
50
|
+
yield t if block_given?
|
51
|
+
add_table_actions(t)
|
26
52
|
end
|
27
53
|
end
|
28
54
|
|
29
55
|
# Adds a set of standard action link column (show, edit, destroy) to the given table.
|
30
56
|
def add_table_actions(table)
|
31
|
-
action_col_show(table)
|
32
57
|
action_col_edit(table)
|
33
58
|
action_col_destroy(table)
|
34
59
|
end
|
60
|
+
|
61
|
+
# Renders the passed attr with a link to the show action for
|
62
|
+
# the current entry.
|
63
|
+
# A block may be given to define the link path for the row entry.
|
64
|
+
def col_show(table, attr, &block)
|
65
|
+
table.attr(attr, table.sort_header(attr)) do |e|
|
66
|
+
link_to(format_attr(e, attr), action_path(e, &block))
|
67
|
+
end
|
68
|
+
end
|
35
69
|
|
36
70
|
# Action link to show the row entry inside a table.
|
37
71
|
# A block may be given to define the link path for the row entry.
|
38
72
|
def action_col_show(table, &block)
|
39
|
-
action_col(table)
|
73
|
+
action_col(table) do |e|
|
74
|
+
link_table_action('zoom-in', action_path(e, &block))
|
75
|
+
end
|
40
76
|
end
|
41
77
|
|
42
78
|
# Action link to edit inside a table.
|
@@ -53,8 +89,8 @@ module CrudHelper
|
|
53
89
|
def action_col_destroy(table, &block)
|
54
90
|
action_col(table) do |e|
|
55
91
|
link_table_action('remove', action_path(e, &block),
|
56
|
-
:confirm => ti(:confirm_delete),
|
57
|
-
|
92
|
+
:data => { :confirm => ti(:confirm_delete),
|
93
|
+
:method => :delete })
|
58
94
|
end
|
59
95
|
end
|
60
96
|
|
@@ -90,8 +126,8 @@ module CrudHelper
|
|
90
126
|
def link_action_destroy(path = nil)
|
91
127
|
path ||= path_args(entry)
|
92
128
|
link_action ti(:"link.delete"), 'remove', path,
|
93
|
-
:confirm => ti(:confirm_delete),
|
94
|
-
|
129
|
+
:data => { :confirm => ti(:confirm_delete),
|
130
|
+
:method => :delete }
|
95
131
|
end
|
96
132
|
|
97
133
|
# Standard link action to the list page.
|
@@ -110,17 +146,23 @@ module CrudHelper
|
|
110
146
|
|
111
147
|
private
|
112
148
|
|
149
|
+
# Get the cancel url for the given object considering options:
|
150
|
+
# 1. Use :cancel_url_new or :cancel_url_edit option, if present
|
151
|
+
# 2. Use :cancel_url option, if present
|
152
|
+
# 3. Use polymorphic_path(object)
|
153
|
+
def get_cancel_url(object, options)
|
154
|
+
record = Array(object).last
|
155
|
+
cancel_url = options.delete(:cancel_url)
|
156
|
+
cancel_url_new = options.delete(:cancel_url_new)
|
157
|
+
cancel_url_edit = options.delete(:cancel_url_edit)
|
158
|
+
url = record.new_record? ? cancel_url_new : cancel_url_edit
|
159
|
+
url || cancel_url || polymorphic_path(object, :returning => true)
|
160
|
+
end
|
161
|
+
|
113
162
|
# If a block is given, call it to get the path for the current row entry.
|
114
163
|
# Otherwise, return the standard path args.
|
115
164
|
def action_path(e, &block)
|
116
165
|
block_given? ? yield(e) : path_args(e)
|
117
166
|
end
|
118
167
|
|
119
|
-
# Returns default attrs for a crud table if no others are passed.
|
120
|
-
def attrs_or_default(attrs)
|
121
|
-
options = attrs.extract_options!
|
122
|
-
attrs = yield if attrs.blank?
|
123
|
-
attrs << options
|
124
|
-
end
|
125
|
-
|
126
168
|
end
|
@@ -9,7 +9,7 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
9
9
|
|
10
10
|
attr_reader :template
|
11
11
|
|
12
|
-
delegate :association, :column_type, :column_property, :captionize, :ta,
|
12
|
+
delegate :association, :column_type, :column_property, :captionize, :ti, :ta, :link_to,
|
13
13
|
:content_tag, :safe_join, :capture, :add_css_class, :assoc_and_id_attr,
|
14
14
|
:to => :template
|
15
15
|
|
@@ -121,6 +121,28 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
121
121
|
add_css_class(html_options, 'multiselect')
|
122
122
|
belongs_to_field(attr, html_options)
|
123
123
|
end
|
124
|
+
|
125
|
+
# Render the error messages for the current form.
|
126
|
+
def error_messages
|
127
|
+
@template.render('shared/error_messages', :errors => @object.errors, :object => @object)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Render a submit button and a cancel link for this form.
|
131
|
+
def standard_actions(cancel_url, submit_label = ti(:"button.save"))
|
132
|
+
content_tag(:div, :class => 'form-actions') do
|
133
|
+
safe_join([submit_button(submit_label), cancel_link(cancel_url)], ' ')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Render a standard submit button with the given label.
|
138
|
+
def submit_button(label = ti(:"button.save"))
|
139
|
+
button(label, :class => 'btn btn-primary')
|
140
|
+
end
|
141
|
+
|
142
|
+
# Render a cancel link pointing to the given url.
|
143
|
+
def cancel_link(url)
|
144
|
+
link_to(ti(:"button.cancel"), url, :class => 'cancel')
|
145
|
+
end
|
124
146
|
|
125
147
|
# Renders a marker if the given attr has to be present.
|
126
148
|
def required_mark(attr)
|
@@ -158,9 +180,11 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
158
180
|
|
159
181
|
# Dispatch methods starting with 'labeled_' to render a label and the corresponding
|
160
182
|
# input field. E.g. labeled_boolean_field(:checked, :class => 'bold')
|
183
|
+
# To add an additional help text, use the help option.
|
184
|
+
# E.g. labeled_boolean_field(:checked, :help => 'Some Help')
|
161
185
|
def method_missing(name, *args)
|
162
186
|
if field_method = labeled_field_method?(name)
|
163
|
-
|
187
|
+
build_labeled_field(field_method, *args)
|
164
188
|
else
|
165
189
|
super(name, *args)
|
166
190
|
end
|
@@ -171,7 +195,12 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
171
195
|
labeled_field_method?(name).present? || super(name)
|
172
196
|
end
|
173
197
|
|
174
|
-
|
198
|
+
# Generates a help block for fields
|
199
|
+
def help_block(text)
|
200
|
+
content_tag(:p, text, :class => 'help-block')
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
175
204
|
|
176
205
|
# Returns true if attr is a non-polymorphic association.
|
177
206
|
# If one or more macros are given, the association must be of this kind.
|
@@ -221,4 +250,12 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
221
250
|
end
|
222
251
|
end
|
223
252
|
|
253
|
+
def build_labeled_field(field_method, *args)
|
254
|
+
options = args.extract_options!
|
255
|
+
help = options.delete(:help)
|
256
|
+
text = send(field_method, *(args<<options)) + required_mark(args.first)
|
257
|
+
text << help_block(help) if help.present?
|
258
|
+
labeled(args.first, text)
|
259
|
+
end
|
260
|
+
|
224
261
|
end
|
@@ -11,7 +11,8 @@ module StandardHelper
|
|
11
11
|
def f(value)
|
12
12
|
case value
|
13
13
|
when Fixnum then number_with_delimiter(value)
|
14
|
-
when Float, BigDecimal then number_with_precision(value, :precision =>
|
14
|
+
when Float, BigDecimal then number_with_precision(value, :precision => t('number.format.precision'),
|
15
|
+
:delimiter => t('number.format.delimiter'))
|
15
16
|
when Date then l(value)
|
16
17
|
when Time then l(value, :format => :time)
|
17
18
|
when true then t(:"global.yes")
|
@@ -78,6 +79,7 @@ module StandardHelper
|
|
78
79
|
# If entries is empty, an appropriate message is rendered.
|
79
80
|
# An options hash may be given as the last argument.
|
80
81
|
def table(entries, *attrs, &block)
|
82
|
+
entries.inspect # force evaluation of relations
|
81
83
|
if entries.present?
|
82
84
|
StandardTableBuilder.table(entries, self, attrs.extract_options!) do |t|
|
83
85
|
t.attrs(*attrs)
|
@@ -88,40 +90,19 @@ module StandardHelper
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
# Renders a
|
93
|
+
# Renders a standard form using StandardFormBuilder.
|
92
94
|
# Before the input fields, the error messages are rendered, if present.
|
93
|
-
|
94
|
-
# If a block is given, custom input fields may be rendered and attrs is ignored.
|
95
|
-
# An options hash may be given as the last argument.
|
96
|
-
def standard_form(object, *attrs, &block)
|
97
|
-
options = attrs.extract_options!
|
95
|
+
def standard_form(object, options = {}, &block)
|
98
96
|
options[:builder] ||= StandardFormBuilder
|
99
97
|
options[:html] ||= {}
|
100
98
|
add_css_class options[:html], 'form-horizontal'
|
101
99
|
|
102
100
|
form_for(object, options) do |form|
|
103
|
-
|
104
|
-
content
|
105
|
-
|
106
|
-
content << if block_given?
|
107
|
-
capture(form, &block)
|
108
|
-
else
|
109
|
-
form.labeled_input_fields(*attrs)
|
110
|
-
end
|
111
|
-
|
112
|
-
content << content_tag(:div, :class => 'form-actions') do
|
113
|
-
form.button(ti(:"button.save"), :class => 'btn btn-primary') +
|
114
|
-
' ' +
|
115
|
-
cancel_link(object)
|
116
|
-
end
|
117
|
-
content.html_safe
|
101
|
+
content = form.error_messages
|
102
|
+
content << capture(form, &block)
|
118
103
|
end
|
119
104
|
end
|
120
105
|
|
121
|
-
def cancel_link(object)
|
122
|
-
link_to(ti(:"button.cancel"), polymorphic_path(object, :returning => true), :class => 'cancel')
|
123
|
-
end
|
124
|
-
|
125
106
|
# Renders a simple unordered list, which will
|
126
107
|
# simply render all passed items or yield them
|
127
108
|
# to your block.
|
@@ -230,7 +211,7 @@ module StandardHelper
|
|
230
211
|
end
|
231
212
|
end
|
232
213
|
|
233
|
-
|
214
|
+
private
|
234
215
|
|
235
216
|
# Helper methods that are not directly called from templates.
|
236
217
|
|