hobo 0.8.8 → 0.8.9
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.
- data/CHANGES.txt +34 -0
- data/Rakefile +30 -24
- data/bin/hobo +30 -10
- data/doctest/hobo/hobo_helper.rdoctest +92 -0
- data/doctest/hobo/lifecycles.rdoctest +261 -0
- data/doctest/scopes.rdoctest +387 -0
- data/dryml_generators/rapid/forms.dryml.erb +3 -3
- data/dryml_generators/rapid/pages.dryml.erb +4 -4
- data/lib/active_record/viewhints_validations_interceptor.rb +1 -1
- data/lib/hobo.rb +1 -1
- data/lib/hobo/accessible_associations.rb +3 -3
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/dryml.rb +10 -0
- data/lib/hobo/dryml/taglib.rb +3 -5
- data/lib/hobo/hobo_helper.rb +3 -1
- data/lib/hobo/include_in_save.rb +1 -0
- data/lib/hobo/lifecycles/actions.rb +6 -2
- data/lib/hobo/model.rb +1 -1
- data/lib/hobo/model_controller.rb +34 -12
- data/lib/hobo/permissions.rb +1 -1
- data/lib/hobo/rapid_helper.rb +3 -0
- data/lib/hobo/scopes/association_proxy_extensions.rb +8 -2
- data/lib/hobo/scopes/automatic_scopes.rb +3 -3
- data/lib/hobo/user_controller.rb +2 -1
- data/rails_generators/hobo/hobo_generator.rb +1 -1
- data/rails_generators/hobo/templates/application.dryml +0 -2
- data/rails_generators/hobo_admin_site/hobo_admin_site_generator.rb +45 -0
- data/rails_generators/hobo_admin_site/templates/admin.css +2 -0
- data/rails_generators/hobo_admin_site/templates/application.dryml +1 -0
- data/rails_generators/hobo_admin_site/templates/controller.rb +13 -0
- data/rails_generators/hobo_admin_site/templates/site_taglib.dryml +32 -0
- data/rails_generators/hobo_admin_site/templates/users_index.dryml +5 -0
- data/rails_generators/hobo_front_controller/hobo_front_controller_generator.rb +7 -1
- data/rails_generators/hobo_front_controller/templates/index.dryml +16 -0
- data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +31 -1
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +5 -3
- data/rails_generators/hobo_rapid/templates/lowpro.js +40 -21
- data/rails_generators/hobo_rapid/templates/themes/clean/public/images/101-3B5F87-ACD3E6.png +0 -0
- data/rails_generators/hobo_rapid/templates/themes/clean/public/images/30-3E547A-242E42.png +0 -0
- data/rails_generators/hobo_rapid/templates/themes/clean/public/images/30-DBE1E5-FCFEF5.png +0 -0
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +12 -4
- data/rails_generators/hobo_subsite/hobo_subsite_generator.rb +1 -1
- data/rails_generators/hobo_user_controller/hobo_user_controller_generator.rb +22 -0
- data/rails_generators/hobo_user_controller/templates/accept_invitation.dryml +5 -0
- data/rails_generators/hobo_user_controller/templates/controller.rb +22 -0
- data/rails_generators/hobo_user_model/hobo_user_model_generator.rb +17 -1
- data/rails_generators/hobo_user_model/templates/invite.erb +9 -0
- data/rails_generators/hobo_user_model/templates/mailer.rb +15 -0
- data/rails_generators/hobo_user_model/templates/model.rb +31 -4
- data/taglibs/rapid_core.dryml +25 -6
- data/taglibs/rapid_forms.dryml +65 -24
- data/taglibs/rapid_lifecycles.dryml +1 -1
- data/taglibs/rapid_navigation.dryml +2 -2
- data/taglibs/rapid_plus.dryml +4 -3
- metadata +151 -210
- data/Manifest +0 -155
- data/hobo.gemspec +0 -46
- data/rails_generators/hobo_rapid/templates/themes/clean/public/images/100-3B5F87-ACD3E6.png +0 -0
@@ -0,0 +1,387 @@
|
|
1
|
+
Hobo Scopes
|
2
|
+
{: .document-title}
|
3
|
+
|
4
|
+
Hobo scopes are an extension of the *named scope* and *dynamic finder*
|
5
|
+
functionality introduced in Rails 2.1, 2.2 and 2.3.
|
6
|
+
|
7
|
+
Most of these scopes work by calling `named_scope` the first time they
|
8
|
+
are invoked. They should work at the same speed as a named scope on
|
9
|
+
subsequent invocations.
|
10
|
+
|
11
|
+
However, this does substantially slow down `method_missing` on your
|
12
|
+
model's class. If `ActiveRecord::Base.method_missing` is used often,
|
13
|
+
you may wish to disable this module. (FIXME: how to do that)
|
14
|
+
|
15
|
+
Contents
|
16
|
+
{: .contents-heading}
|
17
|
+
|
18
|
+
- contents
|
19
|
+
{:toc}
|
20
|
+
|
21
|
+
This document was created using the tool
|
22
|
+
[rubydoctest](http://github.com/tablatom/rubydoctest). This means
|
23
|
+
that this file serves as both documentation and test. As a side
|
24
|
+
effect, it also ensures that errors do not creep into the sample code
|
25
|
+
in this documentation.
|
26
|
+
{.hidden}
|
27
|
+
|
28
|
+
The idea behind rubydoctest is that you should be able to recreate
|
29
|
+
everything in this document from an irb console. It is recommended
|
30
|
+
that you skip down to the [fixture definitions](#fixture_definition).
|
31
|
+
Nobody but the computer needs to read the rest of this section.
|
32
|
+
{.hidden}
|
33
|
+
|
34
|
+
To test Hobo scopes, we're going to need a connection to the database
|
35
|
+
and some sample data. This takes a few lines of code to set up when
|
36
|
+
starting from a blank irb session.
|
37
|
+
{.hidden}
|
38
|
+
|
39
|
+
First off we need to configure ActiveSupport for auto-loading
|
40
|
+
{.hidden}
|
41
|
+
|
42
|
+
>> require 'rubygems'
|
43
|
+
>> require 'activesupport'
|
44
|
+
>> require 'activerecord'
|
45
|
+
>> require 'actionpack'
|
46
|
+
>> require 'action_view'
|
47
|
+
>> require 'action_controller'
|
48
|
+
{.hidden}
|
49
|
+
|
50
|
+
We also need to get ActiveRecord set up with a database connection
|
51
|
+
{.hidden}
|
52
|
+
|
53
|
+
>> mysql_database = "hobofields_doctest"
|
54
|
+
>> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
|
55
|
+
>> system("mysqladmin create #{mysql_database}") or raise "could not create database"
|
56
|
+
>> ActiveRecord::Base.establish_connection(:adapter => "mysql",
|
57
|
+
:database => mysql_database,
|
58
|
+
:host => "localhost")
|
59
|
+
{.hidden}
|
60
|
+
|
61
|
+
Some load path manipulation:
|
62
|
+
{.hidden}
|
63
|
+
|
64
|
+
>> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobofields/lib')
|
65
|
+
>> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobosupport/lib')
|
66
|
+
>> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobo/lib')
|
67
|
+
{.hidden}
|
68
|
+
|
69
|
+
And we'll require hobo:
|
70
|
+
{.hidden}
|
71
|
+
|
72
|
+
>> require 'hobosupport'
|
73
|
+
>> require 'hobofields'
|
74
|
+
>> require 'hobo'
|
75
|
+
>> Hobo::Model.enable
|
76
|
+
{.hidden}
|
77
|
+
|
78
|
+
Let's set up a few models for our testing:
|
79
|
+
|
80
|
+
>>
|
81
|
+
class Person < ActiveRecord::Base
|
82
|
+
hobo_model
|
83
|
+
|
84
|
+
fields do
|
85
|
+
name :string
|
86
|
+
born_at :date
|
87
|
+
code :integer
|
88
|
+
male :boolean
|
89
|
+
timestamps
|
90
|
+
end
|
91
|
+
|
92
|
+
lifecycle(:key_timestamp_field => false) do
|
93
|
+
state :inactive, :active
|
94
|
+
end
|
95
|
+
|
96
|
+
has_many :friendships
|
97
|
+
has_many :friends, :through => :friendships
|
98
|
+
end
|
99
|
+
|
100
|
+
>>
|
101
|
+
class Friendship < ActiveRecord::Base
|
102
|
+
hobo_model
|
103
|
+
belongs_to :person
|
104
|
+
belongs_to :friend, :class_name => "Person"
|
105
|
+
end
|
106
|
+
|
107
|
+
Generate a migration and run it:
|
108
|
+
{.hidden}
|
109
|
+
|
110
|
+
>> ActiveRecord::Migration.class_eval(HoboFields::MigrationGenerator.run[0])
|
111
|
+
>> Person.columns.*.name
|
112
|
+
=> ["id", "name", "born_at", "code", "male", "created_at", "updated_at", "state"]
|
113
|
+
{.hidden}
|
114
|
+
|
115
|
+
And create a couple of fixtures:
|
116
|
+
|
117
|
+
>>
|
118
|
+
Bryan = Person.new(:name => "Bryan", :code => 17,
|
119
|
+
:born_at => Date.new(1973,4,8), :male => true)
|
120
|
+
>> Bryan.state = "active"
|
121
|
+
>> Bryan.save!
|
122
|
+
>>
|
123
|
+
Bethany = Person.new(:name => "Bethany", :code => 42,
|
124
|
+
:born_at => Date.new(1975,5,13), :male => false)
|
125
|
+
>> Bethany.state = "inactive"
|
126
|
+
>> Bethany.save!
|
127
|
+
>> Friendship.new(:person => Bryan, :friend => Bethany).save!
|
128
|
+
|
129
|
+
Hack the `created_at` column to get predictable sorting.
|
130
|
+
|
131
|
+
>> Bethany.created_at = Date.new(2000)
|
132
|
+
>> Bethany.save!
|
133
|
+
|
134
|
+
We're ready to get going.
|
135
|
+
|
136
|
+
# Simple Scopes
|
137
|
+
|
138
|
+
## \_is
|
139
|
+
|
140
|
+
Most Hobo scopes work by appending an appropriate query string to the
|
141
|
+
field name. In this case, the hobo scope function name is the name of
|
142
|
+
your database column, followed by `_is`. It returns an Array of models.
|
143
|
+
|
144
|
+
It works the same as a dynamic finder:
|
145
|
+
|
146
|
+
>> Person.find_all_by_name("Bryan").*.name
|
147
|
+
=> ["Bryan"]
|
148
|
+
>> Person.name_is("Bryan").*.name
|
149
|
+
=> ["Bryan"]
|
150
|
+
>> Person.code_is(17).*.name
|
151
|
+
=> ["Bryan"]
|
152
|
+
>> Person.code_is(99).length
|
153
|
+
=> 0
|
154
|
+
|
155
|
+
## \_is\_not
|
156
|
+
|
157
|
+
But the Hobo scope form allows us to supply several variations
|
158
|
+
|
159
|
+
>> Person.name_is_not("Bryan").*.name
|
160
|
+
=> ["Bethany"]
|
161
|
+
|
162
|
+
## \_contains
|
163
|
+
|
164
|
+
>> Person.name_contains("y").*.name
|
165
|
+
=> ["Bryan", "Bethany"]
|
166
|
+
|
167
|
+
## \_does\_not\_contain
|
168
|
+
|
169
|
+
>> Person.name_does_not_contain("B").*.name
|
170
|
+
=> []
|
171
|
+
|
172
|
+
## \_starts
|
173
|
+
|
174
|
+
>> Person.name_starts("B").*.name
|
175
|
+
=> ["Bryan", "Bethany"]
|
176
|
+
|
177
|
+
## \_does\_not\_start
|
178
|
+
|
179
|
+
>> Person.name_does_not_start("B").length
|
180
|
+
=> 0
|
181
|
+
|
182
|
+
## \_ends
|
183
|
+
|
184
|
+
>> Person.name_ends("y").*.name
|
185
|
+
=> ["Bethany"]
|
186
|
+
|
187
|
+
## \_does\_not\_end
|
188
|
+
|
189
|
+
>> Person.name_does_not_end("y").*.name
|
190
|
+
=> ["Bryan"]
|
191
|
+
|
192
|
+
# Boolean scopes
|
193
|
+
|
194
|
+
## \_
|
195
|
+
|
196
|
+
If you use the name of the column by itself, the column is of type
|
197
|
+
boolean, and no function is already defined on the model class with
|
198
|
+
the name, Hobo scopes adds a dynamic finder to return all records with
|
199
|
+
the boolean column set to `true`
|
200
|
+
|
201
|
+
>> Person.male.*.name
|
202
|
+
=> ["Bryan"]
|
203
|
+
|
204
|
+
## not\_
|
205
|
+
|
206
|
+
You can also search for boolean records that are not `true`. This
|
207
|
+
includes all records that are set to `false` or `NULL`.
|
208
|
+
|
209
|
+
>> Person.not_male.*.name
|
210
|
+
=> ["Bethany"]
|
211
|
+
|
212
|
+
# Date scopes
|
213
|
+
|
214
|
+
Date scopes work only with columns that have a name ending in "_at".
|
215
|
+
The "_at" is omitted when using these finders.
|
216
|
+
|
217
|
+
## \_before
|
218
|
+
|
219
|
+
>> Person.born_before(Date.new(1974)).*.name
|
220
|
+
=> ["Bryan"]
|
221
|
+
|
222
|
+
## \_after
|
223
|
+
|
224
|
+
>> Person.born_after(Date.new(1974)).*.name
|
225
|
+
=> ["Bethany"]
|
226
|
+
|
227
|
+
## \_between
|
228
|
+
|
229
|
+
>> Person.born_between(Date.new(1974), Date.today).*.name
|
230
|
+
=> ["Bethany"]
|
231
|
+
|
232
|
+
# Lifecycle scopes
|
233
|
+
|
234
|
+
If you have a [lifecycle](/manual/lifecycles) defined, each state name
|
235
|
+
can be used as a dynamic finder.
|
236
|
+
|
237
|
+
>> Person.active.*.name
|
238
|
+
=> ["Bryan"]
|
239
|
+
|
240
|
+
# Key scopes
|
241
|
+
|
242
|
+
This isn't very useful:
|
243
|
+
|
244
|
+
>> Person.is(Bryan).*.name
|
245
|
+
=> ["Bryan"]
|
246
|
+
|
247
|
+
But this is:
|
248
|
+
|
249
|
+
>> Person.is_not(Bryan).*.name
|
250
|
+
=> ["Bethany"]
|
251
|
+
|
252
|
+
# Static scopes
|
253
|
+
|
254
|
+
These scopes do not contain the column name.
|
255
|
+
|
256
|
+
## by\_most\_recent
|
257
|
+
|
258
|
+
Sorting on the `created_at` column:
|
259
|
+
|
260
|
+
>> Person.by_most_recent.*.name
|
261
|
+
=> ["Bryan", "Bethany"]
|
262
|
+
|
263
|
+
## recent
|
264
|
+
|
265
|
+
Gives the N most recent items:
|
266
|
+
|
267
|
+
>> Person.recent(1).*.name
|
268
|
+
=> ["Bryan"]
|
269
|
+
|
270
|
+
## limit
|
271
|
+
|
272
|
+
>> Person.limit(1).*.name
|
273
|
+
=> ["Bryan"]
|
274
|
+
|
275
|
+
## order\_by
|
276
|
+
|
277
|
+
>> Person.order_by(:code).*.name
|
278
|
+
=> ["Bryan", "Bethany"]
|
279
|
+
|
280
|
+
## include
|
281
|
+
|
282
|
+
Adding the include function to your query chain has the same effect as
|
283
|
+
the `:include` option to the `find` method.
|
284
|
+
|
285
|
+
>> Person.include(:friends).*.name
|
286
|
+
=> ["Bryan", "Bethany"]
|
287
|
+
|
288
|
+
## search
|
289
|
+
|
290
|
+
Search for text in the specified column(s).
|
291
|
+
|
292
|
+
>> Person.search("B", :name).*.name
|
293
|
+
=> ["Bryan", "Bethany"]
|
294
|
+
|
295
|
+
# Association Scopes
|
296
|
+
|
297
|
+
## with\_
|
298
|
+
|
299
|
+
Find the records that contain the specified record in an association
|
300
|
+
|
301
|
+
>> Person.with_friendship(Friendship.first).*.name
|
302
|
+
=> ["Bryan"]
|
303
|
+
>> Person.with_friend(Bethany).*.name
|
304
|
+
=> ["Bryan"]
|
305
|
+
|
306
|
+
You can also specify multiple records with the plural form
|
307
|
+
|
308
|
+
>> Person.with_friends(Bethany, nil).*.name
|
309
|
+
=> ["Bryan"]
|
310
|
+
|
311
|
+
## without\_
|
312
|
+
|
313
|
+
>> Person.without_friend(Bethany).*.name
|
314
|
+
=> ["Bethany"]
|
315
|
+
>> Person.without_friends(Bethany, nil).*.name
|
316
|
+
=> ["Bethany"]
|
317
|
+
|
318
|
+
|
319
|
+
## \_is
|
320
|
+
|
321
|
+
You can use \_is on a `:has_one` or a `:belongs_to` relationship:
|
322
|
+
|
323
|
+
>> Friendship.person_is(Bryan).*.friend.*.name
|
324
|
+
=> ["Bethany"]
|
325
|
+
|
326
|
+
## \_is\_not
|
327
|
+
|
328
|
+
>> Friendship.person_is_not(Bryan)
|
329
|
+
=> []
|
330
|
+
|
331
|
+
# Scoping Associations
|
332
|
+
|
333
|
+
When defining an association, you can add a scope:
|
334
|
+
|
335
|
+
>>
|
336
|
+
class Person
|
337
|
+
has_many :active_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => :active
|
338
|
+
has_many :inactive_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => :inactive
|
339
|
+
end
|
340
|
+
|
341
|
+
>> Bryan.inactive_friends.*.name
|
342
|
+
=> ["Bethany"]
|
343
|
+
>> Bryan.active_friends.*.name
|
344
|
+
=> []
|
345
|
+
|
346
|
+
or several scopes:
|
347
|
+
|
348
|
+
>>
|
349
|
+
class Person
|
350
|
+
has_many :inactive_female_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => [:inactive, :not_male]
|
351
|
+
has_many :active_female_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => [:active, :not_male]
|
352
|
+
has_many :inactive_male_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => [:inactive, :male]
|
353
|
+
end
|
354
|
+
|
355
|
+
>> Bryan.inactive_female_friends.*.name
|
356
|
+
=> ["Bethany"]
|
357
|
+
>> Bryan.active_female_friends.*.name
|
358
|
+
=> []
|
359
|
+
>> Bryan.inactive_male_friends.*.name
|
360
|
+
=> []
|
361
|
+
|
362
|
+
You can parameterize the scopes:
|
363
|
+
|
364
|
+
>>
|
365
|
+
class Person
|
366
|
+
has_many :y_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => { :name_contains => 'y' }
|
367
|
+
has_many :z_friends, :class_name => "Person", :through => :friendships, :source => :friend, :scope => { :name_contains => 'z' }
|
368
|
+
end
|
369
|
+
|
370
|
+
>> Bryan.y_friends.*.name
|
371
|
+
=> ["Bethany"]
|
372
|
+
>> Bryan.z_friends.*.name
|
373
|
+
=> []
|
374
|
+
|
375
|
+
|
376
|
+
# Chaining
|
377
|
+
|
378
|
+
Like named scopes, Hobo scopes can be chained:
|
379
|
+
|
380
|
+
>> Bryan.inactive_friends.inactive.*.name
|
381
|
+
=> ["Bethany"]
|
382
|
+
|
383
|
+
Clean up our test database:
|
384
|
+
{.hidden}
|
385
|
+
|
386
|
+
>> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
|
387
|
+
{.hidden}
|
@@ -18,7 +18,7 @@ cancel_to_index_page = !cancel_to_index_page && linkable?(:index)
|
|
18
18
|
<% creators.each do |creator| -%>
|
19
19
|
<def tag="<%= creator.name.to_s.dasherize %>-form" polymorphic/>
|
20
20
|
<def tag="<%= creator.name.to_s.dasherize %>-form" for="<%= model.name %>">
|
21
|
-
<form lifecycle="<%= creator.name %>">
|
21
|
+
<form lifecycle="<%= creator.name %>" merge param="default">
|
22
22
|
<error-messages param/>
|
23
23
|
<field-list fields="<%= creator.parameters * ', ' %>" param/>
|
24
24
|
<div param="actions">
|
@@ -31,7 +31,7 @@ cancel_to_index_page = !cancel_to_index_page && linkable?(:index)
|
|
31
31
|
<% transitions.each do |transition| -%>
|
32
32
|
<def tag="<%= transition.name.to_s.dasherize %>-form" polymorphic/>
|
33
33
|
<def tag="<%= transition.name.to_s.dasherize %>-form" for="<%= model.name %>">
|
34
|
-
<form lifecycle="<%= transition.name %>">
|
34
|
+
<form lifecycle="<%= transition.name %>" merge param="default">
|
35
35
|
<error-messages param/>
|
36
36
|
<input type="hidden" name="key" value="&this.lifecycle.provided_key" if="&this.lifecycle.provided_key"/>
|
37
37
|
<field-list fields="<%= transition.parameters * ', ' %>" param/>
|
@@ -42,4 +42,4 @@ cancel_to_index_page = !cancel_to_index_page && linkable?(:index)
|
|
42
42
|
</def>
|
43
43
|
<% end -%>
|
44
44
|
|
45
|
-
<% end # of each_model do -%>
|
45
|
+
<% end # of each_model do -%>
|
@@ -55,7 +55,7 @@ new_form = !new_link && linkable?(model, :create, :method => :post)
|
|
55
55
|
<% if new_form -%>
|
56
56
|
<div param="new-form">
|
57
57
|
<h3 param="new-form-heading">New <%= model_name :title %></h3>
|
58
|
-
<form with="
|
58
|
+
<form with="&@invalid_record || new_for_current_user(<%= model %>)" param/>
|
59
59
|
</div>
|
60
60
|
|
61
61
|
<% end -%>
|
@@ -188,8 +188,8 @@ end
|
|
188
188
|
</preview-with-more:<%= refl.name %>.recent>
|
189
189
|
<% else -%>
|
190
190
|
<section param="<%= refl.name %>-collection-section">
|
191
|
-
<h3 param="<%= refl.name %>-collection"><%= refl.name.to_s.titleize %></h3>
|
192
|
-
<collection:<%= refl.name
|
191
|
+
<h3 param="<%= refl.name %>-collection-heading"><%= refl.name.to_s.titleize %></h3>
|
192
|
+
<collection:<%= refl.name %> param="<%= refl.name %>-collection"/>
|
193
193
|
</section>
|
194
194
|
<% end -%>
|
195
195
|
<% end -%>
|
@@ -250,7 +250,7 @@ new_link = :new.in?(actions)
|
|
250
250
|
<div param="back-to">Back to <a with="&@<%= owner %>"/></div>
|
251
251
|
<% end -%>
|
252
252
|
<% if owner_is_user %>
|
253
|
-
<h2 param="heading"><Your with="
|
253
|
+
<h2 param="heading"><Your with="&@<%= owner %>"/> <%= model_name :title, :plural %></h2>
|
254
254
|
<% else -%>
|
255
255
|
<h2 param="heading"><%= model_name :title, :plural %></h2>
|
256
256
|
<h3 param="subheading">For: <<%= owner_tag %> with="&@<%= owner %>"/></h3>
|
@@ -2,7 +2,7 @@ module Hobo
|
|
2
2
|
module ViewHintsValidationsInterceptor
|
3
3
|
def human_attribute_name(attribute_key_name, opt={})
|
4
4
|
view_hints_field_names = self.view_hints.field_names
|
5
|
-
view_hints_field_names.include?(attribute_key_name.to_sym) ?
|
5
|
+
attribute_key_name!="" && view_hints_field_names.include?(attribute_key_name.to_sym) ?
|
6
6
|
view_hints_field_names[attribute_key_name.to_sym] : super
|
7
7
|
end
|
8
8
|
end
|