hobo 1.3.3 → 1.4.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/{CHANGES.txt → CHANGES-1.3.txt} +0 -0
- data/CHANGES-1.4.txt +678 -0
- data/Rakefile +13 -3
- data/TODO-1.4.txt +69 -0
- data/VERSION +1 -1
- data/app/helpers/hobo_debug_helper.rb +16 -0
- data/app/helpers/hobo_deprecated_helper.rb +45 -0
- data/app/helpers/hobo_helper_base.rb +8 -0
- data/app/helpers/hobo_permissions_helper.rb +136 -0
- data/app/helpers/hobo_route_helper.rb +196 -0
- data/{lib/hobo/helper/translations.rb → app/helpers/hobo_translations_helper.rb} +4 -7
- data/{lib/hobo/helper/translations/normalizer.rb → app/helpers/hobo_translations_normalizer_helper.rb} +3 -10
- data/app/helpers/hobo_type_helper.rb +24 -0
- data/app/helpers/hobo_view_hint_helper.rb +13 -0
- data/hobo.gemspec +3 -3
- data/lib/generators/hobo/admin_subsite/admin_subsite_generator.rb +0 -9
- data/lib/generators/hobo/admin_subsite/templates/application.dryml +2 -0
- data/lib/generators/hobo/admin_subsite/templates/gitkeep +0 -0
- data/lib/generators/hobo/admin_subsite/templates/site.css.erb +9 -0
- data/lib/generators/hobo/admin_subsite/templates/site.js.erb +10 -0
- data/lib/generators/hobo/assets/assets_generator.rb +16 -2
- data/lib/generators/hobo/assets/templates/application.css +9 -0
- data/lib/generators/hobo/assets/templates/application.dryml.erb +0 -5
- data/lib/generators/hobo/assets/templates/application.js +11 -0
- data/lib/generators/hobo/assets/templates/front.css +10 -0
- data/lib/generators/hobo/assets/templates/front.js +11 -0
- data/lib/generators/hobo/assets/templates/front_site.dryml.erb +6 -0
- data/lib/generators/hobo/assets/templates/gitkeep +0 -0
- data/lib/generators/hobo/dev_tweaks/dev_tweaks_generator.rb +31 -0
- data/lib/generators/hobo/i18n/templates/hobo.en.yml +1 -1
- data/lib/generators/hobo/install_plugin/USAGE +3 -0
- data/lib/generators/hobo/install_plugin/install_plugin_generator.rb +36 -0
- data/lib/generators/hobo/plugin.rb +112 -0
- data/lib/generators/hobo/setup_wizard/setup_wizard_generator.rb +31 -14
- data/lib/generators/hobo/subsite.rb +16 -2
- data/lib/generators/hobo/subsite/templates/gitkeep +0 -0
- data/lib/generators/hobo/subsite/templates/site.css.erb +9 -0
- data/lib/generators/hobo/subsite/templates/site.js.erb +10 -0
- data/lib/generators/hobo/subsite_taglib/templates/taglib.dryml.erb +0 -17
- data/lib/generators/hobo/test_framework/test_framework_generator.rb +1 -1
- data/lib/hobo.rb +3 -2
- data/lib/hobo/controller.rb +43 -24
- data/lib/hobo/controller/model.rb +63 -42
- data/lib/hobo/controller/user_base.rb +1 -3
- data/lib/hobo/engine.rb +1 -1
- data/lib/hobo/extensions/active_record/associations/association.rb +36 -0
- data/lib/hobo/extensions/active_record/associations/collection.rb +10 -19
- data/lib/hobo/extensions/active_record/associations/proxy.rb +3 -15
- data/lib/hobo/extensions/active_record/associations/scope.rb +2 -2
- data/lib/hobo/extensions/active_record/permissions.rb +32 -38
- data/lib/hobo/extensions/active_record/relation_with_origin.rb +5 -5
- data/lib/hobo/model.rb +12 -7
- data/lib/hobo/model/accessible_associations.rb +8 -15
- data/lib/hobo/model/lifecycles/creator.rb +1 -1
- data/lib/hobo/model/lifecycles/transition.rb +1 -1
- data/lib/hobo/model/permissions.rb +4 -4
- data/lib/hobo/model/scopes.rb +4 -17
- data/lib/hobo/model/scopes/automatic_scopes.rb +5 -13
- data/lib/hobo/rapid/helper.rb +1 -161
- data/lib/hobo/rapid/taglibs/rapid.dryml +3 -17
- data/test/doctest/hobo/hobo_helper.rdoctest +8 -44
- data/{doctests → test/doctest}/hobo/lifecycles.rdoctest +0 -0
- data/{doctests → test/doctest}/hobo/model.rdoctest +2 -4
- data/{doctests → test/doctest}/hobo/multi_model_forms.rdoctest +3 -24
- data/{doctests → test/doctest}/hobo/scopes.rdoctest +3 -53
- data/test/doctest/prepare_testapp.rb +11 -0
- data/test/irt/generators/admin_subsite.irt +1 -19
- data/test/irt/generators/assets.irt +4 -9
- data/test/irt/generators/controller.irt +0 -3
- data/test/irt/generators/front_controller.irt +0 -5
- data/test/irt/generators/{helper.rb → irt_helper.rb} +2 -2
- data/test/irt/generators/model.irt +1 -12
- data/test/irt/generators/partials/_account_user_model_tests.rb +0 -8
- data/test/irt/generators/partials/_accounts_users_controller_tests.rb +0 -2
- data/test/irt/generators/partials/_default_user_model_tests.rb +0 -8
- data/test/irt/generators/partials/_default_users_controller_tests.rb +0 -2
- data/test/irt/generators/partials/_house_controller_tests.rb +0 -2
- data/test/irt/generators/partials/_house_model_tests.rb +1 -9
- data/test/irt/generators/partials/_subsite_taglib_admin.rb +5 -2
- data/test/irt/generators/partials/_subsite_taglib_admin_invite_only.rb +1 -1
- data/test/irt/generators/partials/_subsite_taglib_noopt.rb +2 -2
- data/test/irt/generators/partials/_subsite_taglib_variables.rb +0 -15
- data/test/irt/generators/partials/_user_mailer_tests.rb +1 -3
- data/test/irt/generators/resource.irt +0 -3
- data/test/irt/generators/subsite.irt +6 -22
- data/test/irt/generators/subsite_taglib.irt +0 -18
- data/test/irt/generators/test_framework.irt +2 -5
- data/test/irt/generators/user_controller.irt +0 -3
- data/test/irt/generators/user_mailer.irt +0 -3
- data/test/irt/generators/user_model.irt +0 -3
- data/test/irt/generators/user_resource.irt +0 -3
- data/test/irt/readme.txt +6 -3
- metadata +116 -159
- data/app/controllers/dev_controller.rb +0 -25
- data/app/views/dev/summary.dryml +0 -102
- data/doctests/prepare_testapp.rb +0 -8
- data/lib/generators/hobo/admin_subsite/templates/admin.css +0 -20
- data/lib/generators/hobo/rapid/USAGE +0 -3
- data/lib/generators/hobo/rapid/rapid_generator.rb +0 -24
- data/lib/generators/hobo/rapid/templates/IE7.js +0 -2
- data/lib/generators/hobo/rapid/templates/blank.gif +0 -0
- data/lib/generators/hobo/rapid/templates/hobo-rapid.css +0 -94
- data/lib/generators/hobo/rapid/templates/hobo-rapid.js +0 -1015
- data/lib/generators/hobo/rapid/templates/ie7-recalc.js +0 -166
- data/lib/generators/hobo/rapid/templates/lowpro.js +0 -339
- data/lib/generators/hobo/rapid/templates/reset.css +0 -95
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/101-3B5F87-ACD3E6.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/30-3E547A-242E42.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/30-DBE1E5-FCFEF5.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/300-ACD3E6-fff.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/50-ACD3E6-fff.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/fieldbg.gif +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/pencil.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/small_close.png +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/images/spinner.gif +0 -0
- data/lib/generators/hobo/rapid/templates/themes/clean/public/stylesheets/clean.css +0 -327
- data/lib/generators/hobo/rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -102
- data/lib/generators/hobo/rapid/templates/themes/clean/views/clean.dryml +0 -10
- data/lib/hobo/helper.rb +0 -460
- data/lib/hobo/rapid/taglibs/rapid_core.dryml +0 -808
- data/lib/hobo/rapid/taglibs/rapid_document_tags.dryml +0 -56
- data/lib/hobo/rapid/taglibs/rapid_editing.dryml +0 -287
- data/lib/hobo/rapid/taglibs/rapid_forms.dryml +0 -1156
- data/lib/hobo/rapid/taglibs/rapid_generics.dryml +0 -48
- data/lib/hobo/rapid/taglibs/rapid_i18n.dryml +0 -173
- data/lib/hobo/rapid/taglibs/rapid_lifecycles.dryml +0 -96
- data/lib/hobo/rapid/taglibs/rapid_navigation.dryml +0 -108
- data/lib/hobo/rapid/taglibs/rapid_pages.dryml +0 -259
- data/lib/hobo/rapid/taglibs/rapid_plus.dryml +0 -247
- data/lib/hobo/rapid/taglibs/rapid_summary.dryml +0 -283
- data/lib/hobo/rapid/taglibs/rapid_support.dryml +0 -102
- data/lib/hobo/rapid/taglibs/rapid_user_pages.dryml +0 -182
- data/test/irt/generators/rapid.irt +0 -29
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require '
|
2
|
+
require 'rdoc/task'
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'tmpdir'
|
5
5
|
|
@@ -9,13 +9,16 @@ $:.unshift File.expand_path('../lib', __FILE__)
|
|
9
9
|
$:.unshift File.expand_path('../../hobo_support/lib', __FILE__)
|
10
10
|
$:.unshift File.expand_path('../../hobo_fields/lib', __FILE__)
|
11
11
|
$:.unshift File.expand_path('../../dryml/lib', __FILE__)
|
12
|
+
|
12
13
|
require 'hobo'
|
13
14
|
|
15
|
+
include Rake::DSL
|
16
|
+
|
14
17
|
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
|
15
18
|
RUBYDOCTEST = ENV['RUBYDOCTEST'] || "#{RUBY} -S rubydoctest"
|
16
19
|
|
17
20
|
GEM_ROOT = File.expand_path('../', __FILE__)
|
18
|
-
TESTAPP_PATH = File.join
|
21
|
+
TESTAPP_PATH = ENV['TESTAPP_PATH'] || File.join(Dir.tmpdir, 'hobo_testapp')
|
19
22
|
BIN = File.expand_path('../bin/hobo', __FILE__)
|
20
23
|
require 'hobo_support/common_tasks'
|
21
24
|
include HoboSupport::CommonTasks
|
@@ -37,9 +40,16 @@ Rake::TestTask.new(:test) { |t|
|
|
37
40
|
namespace "test" do
|
38
41
|
desc "Run the doctests"
|
39
42
|
task :doctest do |t|
|
40
|
-
files=Dir['
|
43
|
+
files=Dir['test/doctest/**/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
|
41
44
|
exit(1) if !system("#{RUBYDOCTEST} #{files}")
|
42
45
|
end
|
46
|
+
|
47
|
+
desc "Run the irt tests"
|
48
|
+
task :irt => :prepare_testapp do |t|
|
49
|
+
chdir TESTAPP_PATH
|
50
|
+
sh %(irt #{File.expand_path('.',GEM_ROOT)})
|
51
|
+
end
|
52
|
+
|
43
53
|
end
|
44
54
|
|
45
55
|
# --- RDoc --- #
|
data/TODO-1.4.txt
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
## regressions
|
4
|
+
|
5
|
+
* after-submit, sortable-input-many and name-many do not work
|
6
|
+
* Hobo 1.4 breaks default_scope. If you're setting the order, you
|
7
|
+
can use Hobo's set_default_order as a stopgap although once it's
|
8
|
+
fixed please switch back to default_scope as set_default_order
|
9
|
+
is deprecated.
|
10
|
+
* remote-method-button, create-button, update-button,
|
11
|
+
transition-button: normal usages of these tags work, but they do
|
12
|
+
not work if you ask them to do AJAX
|
13
|
+
* live-search works, but it's not 'live'. You have to press return
|
14
|
+
to start the search
|
15
|
+
* remove-button, remote-method-button, create-button & update-button
|
16
|
+
used to display inline but now display as a block. In other
|
17
|
+
words, they now display one per line rather than several in a
|
18
|
+
single line.
|
19
|
+
* the rapid_summary tags have been moved out
|
20
|
+
of core Hobo into their own plugin,
|
21
|
+
https://github.com/Hobo/hobo_summary, which is not yet in a working state
|
22
|
+
|
23
|
+
## documentation
|
24
|
+
|
25
|
+
* document themes/plugins
|
26
|
+
* FAQ
|
27
|
+
* agility
|
28
|
+
* admin subsite
|
29
|
+
* books
|
30
|
+
* ajax manual section
|
31
|
+
|
32
|
+
## Cookbook
|
33
|
+
|
34
|
+
* captcha
|
35
|
+
* search
|
36
|
+
* actually use Hobo 1.4's new caching abilities
|
37
|
+
* auto-link tags in manual
|
38
|
+
* create fakedef manual entries for DRYML tags not in taglibs entry
|
39
|
+
|
40
|
+
## new features that aren't "done"
|
41
|
+
|
42
|
+
* create_response: mirror update_response
|
43
|
+
* taglib cleanup
|
44
|
+
* clean_sidemenu -> plugin
|
45
|
+
* nested-cache: csrf workaround
|
46
|
+
* nested-cache: enhanced sweeper version
|
47
|
+
* monkey patch will_paginate if my patches are not upstreamed
|
48
|
+
|
49
|
+
It's quite likely that some of the new tag definitions are missing
|
50
|
+
useful id, class, merge or param attributes. This doesn't impact core
|
51
|
+
functionality, but it does limit your ability to extend the tags. If
|
52
|
+
you notice any such omissions, please let us know, it is easy to fix..
|
53
|
+
|
54
|
+
## stuff that we really want to do
|
55
|
+
|
56
|
+
* fixup deprecation warnings
|
57
|
+
* port to Rails 3.2 and/or 4.0
|
58
|
+
* nuke any remaining prototype code
|
59
|
+
* add a sane default for non-AJAX JSON requests.
|
60
|
+
* trawl the lighthouse && pull requests
|
61
|
+
* steal the tags from Portal
|
62
|
+
* fixup hobo-contrib
|
63
|
+
|
64
|
+
## would be nice:
|
65
|
+
|
66
|
+
* parametrize the clean theme
|
67
|
+
* create a bootstrap theme
|
68
|
+
* add theme chooser to setup wizard
|
69
|
+
* add support for has-one
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0.pre2
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module HoboDebugHelper
|
2
|
+
extend HoboHelperBase
|
3
|
+
protected
|
4
|
+
def abort_with(*args)
|
5
|
+
raise args.*.pretty_inspect.join("-------\n")
|
6
|
+
end
|
7
|
+
|
8
|
+
def log_debug(*args)
|
9
|
+
return if not logger
|
10
|
+
logger.debug("\n### DRYML Debug ###")
|
11
|
+
logger.debug(args.*.pretty_inspect.join("-------\n"))
|
12
|
+
logger.debug("DRYML THIS = #{this.typed_id rescue this.inspect}")
|
13
|
+
logger.debug("###################\n")
|
14
|
+
args.first unless args.empty?
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# as far as I can tell, these functions are no longer used. It's
|
2
|
+
# theoretically possible that they are used in user apps somewhere,
|
3
|
+
# but unlikely
|
4
|
+
module HoboDeprecatedHelper
|
5
|
+
if Rails.application.config.hobo.include_deprecated_helper
|
6
|
+
protected
|
7
|
+
def uid
|
8
|
+
@hobo_uid ||= 0
|
9
|
+
@hobo_uid += 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_elements_class(updates)
|
13
|
+
'update::'+comma_split(updates).join(':') unless updates.blank?
|
14
|
+
end
|
15
|
+
|
16
|
+
def js_str(s)
|
17
|
+
if s.is_a? Hobo::RawJs
|
18
|
+
s.to_s
|
19
|
+
else
|
20
|
+
"'" + s.to_s.gsub("'"){"\\'"} + "'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def make_params_js(*args)
|
26
|
+
("'" + make_params(*args) + "'").sub(/ \+ ''$/,'')
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def nl_to_br(s)
|
31
|
+
s.to_s.gsub("\n", "<br/>") if s
|
32
|
+
end
|
33
|
+
|
34
|
+
def transpose_with_field(field, collection=nil)
|
35
|
+
collection ||= this
|
36
|
+
matrix = collection.map {|obj| obj.send(field) }
|
37
|
+
max_length = matrix.*.length.max
|
38
|
+
matrix = matrix.map do |a|
|
39
|
+
a + [nil] * (max_length - a.length)
|
40
|
+
end
|
41
|
+
matrix.transpose
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module HoboPermissionsHelper
|
2
|
+
extend HoboHelperBase
|
3
|
+
protected
|
4
|
+
|
5
|
+
def current_user
|
6
|
+
# simple one-hit-per-request cache
|
7
|
+
@current_user ||= begin
|
8
|
+
id = session._?[:user]
|
9
|
+
(id && Hobo::Model.find_by_typed_id(id) rescue nil) || ::Guest.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def logged_in?
|
15
|
+
!current_user.guest?
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def can_create?(object=this)
|
20
|
+
if object.is_a?(Class) and object < ActiveRecord::Base
|
21
|
+
object = object.new
|
22
|
+
elsif (refl = object.try.proxy_reflection) && refl.macro == :has_many
|
23
|
+
if Hobo.simple_has_many_association?(object)
|
24
|
+
object = object.new
|
25
|
+
object.set_creator(current_user)
|
26
|
+
else
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
object.creatable_by?(current_user)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def can_update?(object=this)
|
35
|
+
object.updatable_by?(current_user)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def can_edit?(*args)
|
40
|
+
object, field = if args.empty?
|
41
|
+
if this.respond_to?(:editable_by?) && !this_field_reflection
|
42
|
+
[this, nil]
|
43
|
+
elsif this_parent && this_field
|
44
|
+
[this_parent, this_field]
|
45
|
+
else
|
46
|
+
[this, nil]
|
47
|
+
end
|
48
|
+
elsif args.length == 2
|
49
|
+
args
|
50
|
+
else
|
51
|
+
[this, args.first]
|
52
|
+
end
|
53
|
+
|
54
|
+
if !field && (origin = object.try.origin)
|
55
|
+
object, field = origin, object.origin_attribute
|
56
|
+
end
|
57
|
+
|
58
|
+
object.editable_by?(current_user, field)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def can_delete?(object=this)
|
63
|
+
object.destroyable_by?(current_user)
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
def can_call?(*args)
|
69
|
+
method = args.last
|
70
|
+
object = args.length == 2 ? args.first : this
|
71
|
+
|
72
|
+
object.method_callable_by?(current_user, method)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# can_view? has special behaviour if it's passed a class or an
|
77
|
+
# association-proxy -- it instantiates the class, or creates a new
|
78
|
+
# instance "in" the association, and tests the permission of this
|
79
|
+
# object. This means the permission methods in models can't rely
|
80
|
+
# on the instance being properly initialised. But it's important
|
81
|
+
# that it works like this because, in the case of an association
|
82
|
+
# proxy, we don't want to loose the information that the object
|
83
|
+
# belongs_to the proxy owner.
|
84
|
+
def can_view?(*args)
|
85
|
+
# TODO: Man does this need a big cleanup!
|
86
|
+
|
87
|
+
if args.empty?
|
88
|
+
# if we're repeating over an array, this_field ends up with the current index. Is this useful to anybody?
|
89
|
+
if this_parent && this_field && !this_field.is_a?(Integer)
|
90
|
+
object = this_parent
|
91
|
+
field = this_field
|
92
|
+
else
|
93
|
+
object = this
|
94
|
+
end
|
95
|
+
elsif args.first.is_one_of?(String, Symbol)
|
96
|
+
object = this
|
97
|
+
field = args.first
|
98
|
+
else
|
99
|
+
object, field = args
|
100
|
+
end
|
101
|
+
|
102
|
+
if field
|
103
|
+
# Field can be a dot separated path
|
104
|
+
if field.is_a?(String) && (path = field.split(".")).length > 1
|
105
|
+
_, _, object = Dryml.get_field_path(object, path[0..-2])
|
106
|
+
field = path.last
|
107
|
+
end
|
108
|
+
elsif (origin = object.try.origin)
|
109
|
+
object, field = origin, object.origin_attribute
|
110
|
+
end
|
111
|
+
|
112
|
+
@can_view_cache ||= {}
|
113
|
+
@can_view_cache[ [object, field] ] ||=
|
114
|
+
if !object.respond_to?(:viewable_by?)
|
115
|
+
true
|
116
|
+
elsif object.viewable_by?(current_user, field)
|
117
|
+
# If possible, we also check if the current *value* of the field is viewable
|
118
|
+
if field.is_one_of?(Symbol, String) && (v = object.send(field)) && v.respond_to?(:viewable_by?)
|
119
|
+
if v.is_a?(Array)
|
120
|
+
v.new_candidate.viewable_by?(current_user, nil)
|
121
|
+
else
|
122
|
+
v.viewable_by?(current_user, nil)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
true
|
126
|
+
end
|
127
|
+
else
|
128
|
+
false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def select_viewable(collection=this)
|
134
|
+
collection.select {|x| can_view?(x)}
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module HoboRouteHelper
|
2
|
+
extend HoboHelperBase
|
3
|
+
protected
|
4
|
+
def base_url
|
5
|
+
"#{Rails.application.config.action_controller.relative_url_root}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def controller_for(obj)
|
9
|
+
if obj.is_a? Class
|
10
|
+
obj.name.underscore.pluralize
|
11
|
+
else
|
12
|
+
obj.class.name.underscore.pluralize
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def subsite
|
18
|
+
params[:controller]._?.match(/([^\/]+)\//)._?[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
IMPLICIT_ACTIONS = [:index, :show, :create, :update, :destroy]
|
22
|
+
|
23
|
+
def object_url(obj, *args)
|
24
|
+
params = args.extract_options!
|
25
|
+
action = args.first._?.to_sym
|
26
|
+
options, params = params.partition_hash([:subsite, :method, :format])
|
27
|
+
options[:subsite] ||= self.subsite
|
28
|
+
subsite, method = options.get :subsite, :method
|
29
|
+
|
30
|
+
if obj.respond_to?(:member_class) && obj.respond_to?(:origin) && obj.origin
|
31
|
+
# Asking for URL of a collection, e.g. category/1/adverts or category/1/adverts/new
|
32
|
+
|
33
|
+
refl = obj.origin.class.reverse_reflection(obj.origin_attribute)
|
34
|
+
owner_name = refl.name.to_s
|
35
|
+
owner_name = owner_name.singularize if refl.macro == :has_many
|
36
|
+
if action == :new
|
37
|
+
action_path = "#{obj.origin_attribute}/new"
|
38
|
+
action = :"new_for_#{owner_name}"
|
39
|
+
elsif action.nil?
|
40
|
+
action_path = obj.origin_attribute
|
41
|
+
if method.to_s == 'post'
|
42
|
+
action = :"create_for_#{owner_name}"
|
43
|
+
else
|
44
|
+
O action = :"index_for_#{owner_name}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
klass = obj.member_class
|
48
|
+
obj = obj.origin
|
49
|
+
else
|
50
|
+
action ||= case options[:method].to_s
|
51
|
+
when 'put'; :update
|
52
|
+
when 'post'; :create
|
53
|
+
when 'delete'; :destroy
|
54
|
+
else; obj.is_a?(Class) ? :index : :show
|
55
|
+
end
|
56
|
+
|
57
|
+
if options[:method].to_s == 'post' && obj.try.new_record?
|
58
|
+
# Asking for url to post new record to
|
59
|
+
obj = obj.class
|
60
|
+
end
|
61
|
+
|
62
|
+
klass = if obj.is_a?(Class)
|
63
|
+
obj
|
64
|
+
elsif obj.respond_to?(:member_class)
|
65
|
+
obj.member_class # We get here if we're passed a scoped class
|
66
|
+
else
|
67
|
+
obj.class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if Hobo::Routes.linkable?(klass, action, options)
|
72
|
+
|
73
|
+
url = base_url_for(obj, subsite, action)
|
74
|
+
url += "/#{action_path || action}" unless action.in?(IMPLICIT_ACTIONS)
|
75
|
+
|
76
|
+
params = make_params(params)
|
77
|
+
params.blank? ? url : "#{url}?#{params}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def linkable?(*args)
|
83
|
+
options = args.extract_options!
|
84
|
+
target = args.empty? || args.first.is_a?(Symbol) ? this : args.shift
|
85
|
+
action = args.first
|
86
|
+
return false if action.nil? && target.try.new_record?
|
87
|
+
|
88
|
+
if target.respond_to?(:member_class) && (origin = target.try.origin)
|
89
|
+
klass = origin.class
|
90
|
+
action = if action == :new
|
91
|
+
"new_#{target.origin_attribute.to_s.singularize}"
|
92
|
+
elsif action.nil?
|
93
|
+
target.origin_attribute
|
94
|
+
end
|
95
|
+
elsif target.is_a?(Class)
|
96
|
+
klass = target
|
97
|
+
action ||= :index
|
98
|
+
else
|
99
|
+
klass = target.class
|
100
|
+
action ||= :show
|
101
|
+
end
|
102
|
+
|
103
|
+
Hobo::Routes.linkable?(klass, action, options.reverse_merge(:subsite => subsite))
|
104
|
+
end
|
105
|
+
|
106
|
+
def base_url_for(object, subsite, action)
|
107
|
+
path = object.to_url_path or Hobo::Error.new("cannot create url for #{object.inspect} (#{object.class})")
|
108
|
+
"#{base_url}#{'/' + subsite unless subsite.blank?}/#{path}"
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def recognize_page_path
|
113
|
+
# round tripping params through the router will remove
|
114
|
+
# unnecessary params
|
115
|
+
Rails.application.routes.recognize_path(params[:page_path] || url_for(params))
|
116
|
+
end
|
117
|
+
|
118
|
+
def url_for_page_path(options={})
|
119
|
+
url_for recognize_page_path.merge(options)
|
120
|
+
end
|
121
|
+
|
122
|
+
def controller_action_from_page_path
|
123
|
+
recognize_page_path.values_at(:controller,:action)
|
124
|
+
end
|
125
|
+
|
126
|
+
def defined_route?(r)
|
127
|
+
@view.respond_to?("#{r}_url")
|
128
|
+
end
|
129
|
+
|
130
|
+
def _as_params(name, obj)
|
131
|
+
if obj.is_a? Array
|
132
|
+
obj.map {|x| _as_params("#{name}[]", x)}.join("&")
|
133
|
+
elsif obj.is_a? Hash
|
134
|
+
obj.map {|k,v| _as_params("#{name}[#{k}]", v)}.join("&")
|
135
|
+
elsif obj.is_a? Hobo::RawJs
|
136
|
+
"#{name}=' + #{obj} + '"
|
137
|
+
else
|
138
|
+
v = if obj.is_one_of?(ActiveRecord::Base, Array)
|
139
|
+
"@" + typed_id(obj)
|
140
|
+
else
|
141
|
+
obj.to_s.gsub("'"){"\\'"}
|
142
|
+
end
|
143
|
+
"#{name}=#{v}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def make_params(*hashes)
|
148
|
+
hash = {}
|
149
|
+
hashes.each {|h| hash.update(h) if h}
|
150
|
+
hash.map {|k,v| _as_params(k, v)}.join("&")
|
151
|
+
end
|
152
|
+
|
153
|
+
def current_page_url
|
154
|
+
request.fullpath.match(/^([^?]*)/)._?[1]
|
155
|
+
end
|
156
|
+
|
157
|
+
# Login url for a given user record or user class
|
158
|
+
def forgot_password_url(user_class=Hobo::Model::UserBase.default_user_model)
|
159
|
+
send("#{user_class.name.underscore}_forgot_password_url") rescue nil
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# Login url for a given user record or user class
|
164
|
+
def login_url(user_class=Hobo::Model::UserBase.default_user_model)
|
165
|
+
send("#{user_class.name.underscore}_login_url") rescue nil
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
# Sign-up url for a given user record or user class
|
170
|
+
def signup_url(user_class=Hobo::Model::UserBase.default_user_model)
|
171
|
+
send("#{user_class.name.underscore}_signup_url") rescue nil
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Login url for a given user record or user class
|
176
|
+
def logout_url(user_or_class=nil)
|
177
|
+
c = if user_or_class.nil?
|
178
|
+
current_user.class
|
179
|
+
elsif user_or_class.is_a?(Class)
|
180
|
+
user_or_class
|
181
|
+
else
|
182
|
+
user_or_class.class
|
183
|
+
end
|
184
|
+
send("#{c.name.underscore}_logout_url") rescue nil
|
185
|
+
end
|
186
|
+
|
187
|
+
def new_for_current_user(model_or_assoc=nil)
|
188
|
+
model_or_assoc ||= this
|
189
|
+
if model_or_assoc.respond_to?(:new_candidate)
|
190
|
+
model_or_assoc.user_new_candidate(current_user)
|
191
|
+
else
|
192
|
+
model_or_assoc.user_new(current_user)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|