Commit 48c7a14e1352c12068961b181196222d95aabc2c
1 parent
d3a8294d
Exists in
master
and in
1 other branch
added josevalim's inherited resources for RESTful controllers
Showing
35 changed files
with
4937 additions
and
0 deletions
Show diff stats
vendor/gems/josevalim-inherited_resources-0.8.5/.specification
0 → 100644
... | ... | @@ -0,0 +1,104 @@ |
1 | +--- !ruby/object:Gem::Specification | |
2 | +name: josevalim-inherited_resources | |
3 | +version: !ruby/object:Gem::Version | |
4 | + version: 0.8.5 | |
5 | +platform: ruby | |
6 | +authors: | |
7 | +- "Jos\xC3\xA9 Valim" | |
8 | +autorequire: | |
9 | +bindir: bin | |
10 | +cert_chain: [] | |
11 | + | |
12 | +date: 2009-07-24 00:00:00 -04:00 | |
13 | +default_executable: | |
14 | +dependencies: [] | |
15 | + | |
16 | +description: Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important. | |
17 | +email: jose.valim@gmail.com | |
18 | +executables: [] | |
19 | + | |
20 | +extensions: [] | |
21 | + | |
22 | +extra_rdoc_files: | |
23 | +- README | |
24 | +files: | |
25 | +- CHANGELOG | |
26 | +- MIT-LICENSE | |
27 | +- README | |
28 | +- Rakefile | |
29 | +- VERSION | |
30 | +- lib/inherited_resources.rb | |
31 | +- lib/inherited_resources/actions.rb | |
32 | +- lib/inherited_resources/base.rb | |
33 | +- lib/inherited_resources/base_helpers.rb | |
34 | +- lib/inherited_resources/belongs_to_helpers.rb | |
35 | +- lib/inherited_resources/class_methods.rb | |
36 | +- lib/inherited_resources/dumb_responder.rb | |
37 | +- lib/inherited_resources/has_scope_helpers.rb | |
38 | +- lib/inherited_resources/polymorphic_helpers.rb | |
39 | +- lib/inherited_resources/respond_to.rb | |
40 | +- lib/inherited_resources/singleton_helpers.rb | |
41 | +- lib/inherited_resources/url_helpers.rb | |
42 | +- test/respond_to_test.rb | |
43 | +- test/customized_belongs_to_test.rb | |
44 | +- test/nested_belongs_to_test.rb | |
45 | +- test/base_test.rb | |
46 | +- test/redirect_to_test.rb | |
47 | +- test/has_scope_test.rb | |
48 | +- test/class_methods_test.rb | |
49 | +- test/aliases_test.rb | |
50 | +- test/flash_test.rb | |
51 | +- test/url_helpers_test.rb | |
52 | +- test/base_helpers_test.rb | |
53 | +- test/belongs_to_test.rb | |
54 | +- test/polymorphic_test.rb | |
55 | +- test/defaults_test.rb | |
56 | +- test/singleton_test.rb | |
57 | +- test/optional_belongs_to_test.rb | |
58 | +- test/test_helper.rb | |
59 | +has_rdoc: true | |
60 | +homepage: http://github.com/josevalim/inherited_resources | |
61 | +licenses: [] | |
62 | + | |
63 | +post_install_message: | |
64 | +rdoc_options: | |
65 | +- --charset=UTF-8 | |
66 | +require_paths: | |
67 | +- lib | |
68 | +required_ruby_version: !ruby/object:Gem::Requirement | |
69 | + requirements: | |
70 | + - - ">=" | |
71 | + - !ruby/object:Gem::Version | |
72 | + version: "0" | |
73 | + version: | |
74 | +required_rubygems_version: !ruby/object:Gem::Requirement | |
75 | + requirements: | |
76 | + - - ">=" | |
77 | + - !ruby/object:Gem::Version | |
78 | + version: "0" | |
79 | + version: | |
80 | +requirements: [] | |
81 | + | |
82 | +rubyforge_project: inherited_resources | |
83 | +rubygems_version: 1.3.4 | |
84 | +signing_key: | |
85 | +specification_version: 3 | |
86 | +summary: Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important. | |
87 | +test_files: | |
88 | +- test/respond_to_test.rb | |
89 | +- test/customized_belongs_to_test.rb | |
90 | +- test/nested_belongs_to_test.rb | |
91 | +- test/base_test.rb | |
92 | +- test/redirect_to_test.rb | |
93 | +- test/has_scope_test.rb | |
94 | +- test/class_methods_test.rb | |
95 | +- test/aliases_test.rb | |
96 | +- test/flash_test.rb | |
97 | +- test/url_helpers_test.rb | |
98 | +- test/base_helpers_test.rb | |
99 | +- test/belongs_to_test.rb | |
100 | +- test/polymorphic_test.rb | |
101 | +- test/defaults_test.rb | |
102 | +- test/singleton_test.rb | |
103 | +- test/optional_belongs_to_test.rb | |
104 | +- test/test_helper.rb | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/CHANGELOG
0 → 100644
... | ... | @@ -0,0 +1,95 @@ |
1 | +# Version 0.8 | |
2 | + | |
3 | +* Fixed a small bug on optional belongs to with namespaced controllers. | |
4 | +* Allow a parameter to be given to collection_url in polymorphic cases to replace | |
5 | + the parent. | |
6 | +* Allow InheritedResources to be called without inheritance. | |
7 | +* Ensure that controllers that inherit from a controller with InheritedResources | |
8 | + works properly. | |
9 | + | |
10 | +# Version 0.7 | |
11 | + | |
12 | +* Allow procs as default value in has scope to be able to use values from session, for example. | |
13 | +* Allow blocks with arity 0 or -1 to be given as the redirect url: | |
14 | + | |
15 | + def destroy | |
16 | + destroy!{ project_url(@project) } | |
17 | + end | |
18 | + | |
19 | +* Allow interpolation_options to be set in the application controller. | |
20 | +* Added has_scope to controller (an interface for named_scopes). | |
21 | +* Added polymorphic_belongs_to, optional_belongs_to and singleton_belongs_to | |
22 | + as quick methods. | |
23 | +* Only load belongs_to, singleton and polymorphic helpers if they are actually | |
24 | + required. base_helpers, class_methods, dumb_responder and url_helpers are loaded | |
25 | + when you inherited from base for the first time. | |
26 | + | |
27 | +# Version 0.6 | |
28 | + | |
29 | +* Ensure that the default template is not rendered if the default_template_format | |
30 | + is not accepted. This is somehow related with the security breach report: | |
31 | + | |
32 | + http://www.rorsecurity.info/journal/2009/4/24/hidden-actions-render-templates.html | |
33 | + | |
34 | + IR forbids based on mime types. For example: respond_to :html, :except => :index | |
35 | + ensures that the index.html.erb view is not rendered, making your IR controllers | |
36 | + safer. | |
37 | + | |
38 | +* Fixed a bug that happens only when format.xml is given to blocks and then it | |
39 | + acts as default, instead of format.html. | |
40 | +* Fixed a strange bug where when you have create.html.erb or update.html.erb, | |
41 | + it makes IE6 and IE7 return unprocessable entity (because they send Mime::ALL). | |
42 | +* Stop rescueing any error when constantizing the resource class and allow | |
43 | + route_prefix to be nil. | |
44 | +* Cleaned up tests and responder structure. Whenever you pass a block to aliases | |
45 | + and this block responds to the request, the other blocks are not parsed improving performance. | |
46 | +* [BACKWARDS INCOMPATIBLE] By default, Inherited Resources respond only :html requests. | |
47 | +* Added a quick way to overwrite the redirect to url in :create, :update and :destroy. | |
48 | + | |
49 | +# Version 0.5 | |
50 | + | |
51 | +* Decoupled routes name from :instance_name and :collection_name. This way we | |
52 | + have more flexibility. Use route_instance_name and route_collection_name to | |
53 | + to change routes. | |
54 | +* Avoid calling human_name on nil when a resource class is not defined. | |
55 | +* Only call I18n if it's defined. | |
56 | + | |
57 | +# Version 0.4 | |
58 | + | |
59 | +* Dealing with namespaced controllers out of the box. | |
60 | +* Added support to namespaced routes through :route_prefix. | |
61 | +* Added fix when resource_url is not defined. | |
62 | +* Added better handling for namespaced controllers. | |
63 | +* Added flash messages scoped by namespaced controllers. | |
64 | +* Deprecated {{resource}} in I18n, use {{resource_name}} instead. | |
65 | +* rspec bug fix is not automatically required anymore. User has to do it | |
66 | + explicitly. | |
67 | +* Added a file which fix a rspec bug when render is called inside a method | |
68 | + which receives a block. | |
69 | +* parent? does not take begin_of_association_chain into account anymore | |
70 | +* Added options to url helpers. | |
71 | +* Added :optional to belongs_to associations. It allows you to deal with | |
72 | + categories/1/products/2 and /products/2 with just one controller. | |
73 | +* Cleaned up tests. | |
74 | + | |
75 | +# Version 0.3 | |
76 | + | |
77 | +* Minor bump after three bug fixes. | |
78 | +* Bug fix when showing warning of constant redefinition. | |
79 | +* Bug fix with ApplicationController not being unloaded properly on development. | |
80 | +* Bug fix when having root singleton resources. Calling collection_url would | |
81 | + raise "NoMethodError _url", not it will call root_url. | |
82 | +* More comments on UrlHelpers. | |
83 | + | |
84 | +# Version 0.2 | |
85 | + | |
86 | +* Bug fix when ApplicationController is already loaded when we load respond_to. | |
87 | +* Added support success/failure blocks. | |
88 | +* Eager loading of files to work properly in multithreaded environments. | |
89 | + | |
90 | +# Version 0.1 | |
91 | + | |
92 | +* Added more helper_methods. | |
93 | +* Added Rails 2.3.0 and changed tests to work with ActionController::TestCase. | |
94 | +* First release. Support to I18n, singleton controllers, polymorphic | |
95 | +controllers, belongs_to, nested_belongs_to and url helpers. | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/MIT-LICENSE
0 → 100644
... | ... | @@ -0,0 +1,20 @@ |
1 | +Copyright (c) 2009 José Valim | |
2 | + | |
3 | +Permission is hereby granted, free of charge, to any person obtaining | |
4 | +a copy of this software and associated documentation files (the | |
5 | +"Software"), to deal in the Software without restriction, including | |
6 | +without limitation the rights to use, copy, modify, merge, publish, | |
7 | +distribute, sublicense, and/or sell copies of the Software, and to | |
8 | +permit persons to whom the Software is furnished to do so, subject to | |
9 | +the following conditions: | |
10 | + | |
11 | +The above copyright notice and this permission notice shall be | |
12 | +included in all copies or substantial portions of the Software. | |
13 | + | |
14 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
15 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
16 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
17 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
18 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
19 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
20 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ... | ... |
... | ... | @@ -0,0 +1,517 @@ |
1 | +Inherited Resources | |
2 | +License: MIT | |
3 | +Version: 0.8.5 | |
4 | + | |
5 | +You can also read this README in pretty html at the GitHub project Wiki page: | |
6 | + | |
7 | + http://wiki.github.com/josevalim/inherited_resources | |
8 | + | |
9 | +Description | |
10 | +----------- | |
11 | + | |
12 | +Inherited Resources speeds up development by making your controllers inherit | |
13 | +all restful actions so you just have to focus on what is important. It makes | |
14 | +your controllers more powerful and cleaner at the same time. | |
15 | + | |
16 | +Plus, making your controllers follow a pattern, it helps you to write better | |
17 | +code by following fat models and skinny controllers convention. | |
18 | + | |
19 | +Inherited Resources is tested and compatible with Rails 2.2.x and Rails 2.3.x. | |
20 | + | |
21 | +keywords: resources, controller, singleton, belongs_to, polymorphic, named_scope and I18n | |
22 | + | |
23 | +Installation | |
24 | +------------ | |
25 | + | |
26 | +Install Inherited Resources is very easy. It is stored in GitHub, so just run | |
27 | +the following: | |
28 | + | |
29 | + gem sources -a http://gems.github.com | |
30 | + sudo gem install josevalim-inherited_resources | |
31 | + | |
32 | +If you want it as plugin, just do: | |
33 | + | |
34 | + script/plugin install git://github.com/josevalim/inherited_resources.git | |
35 | + | |
36 | +rspec-rails <= 1.1.12 known bug | |
37 | +------------------------------- | |
38 | + | |
39 | +InheritedResources has a known bug with rspec-rails. Please upgrade your rspec | |
40 | +version or use the fix which ships with InheritedResources: | |
41 | + | |
42 | + require 'inherited_resources/spec' | |
43 | + | |
44 | +Basic Usage | |
45 | +----------- | |
46 | + | |
47 | +To use Inherited Resources you just have to inherit (duh) it: | |
48 | + | |
49 | + class ProjectsController < InheritedResources::Base | |
50 | + end | |
51 | + | |
52 | +And all actions are defined and working, check it! Your projects collection | |
53 | +(in the index action) is still available in the instance variable @projects | |
54 | +and your project resource (all other actions) is available as @ project. | |
55 | + | |
56 | +The next step is to define which mime types this controller provides: | |
57 | + | |
58 | + class ProjectsController < InheritedResources::Base | |
59 | + respond_to :html, :xml, :json | |
60 | + end | |
61 | + | |
62 | +You can also specify them based per action: | |
63 | + | |
64 | + class ProjectsController < InheritedResources::Base | |
65 | + respond_to :html, :xml, :json | |
66 | + respond_to :js, :only => :create | |
67 | + respond_to :iphone, :except => [ :edit, :update ] | |
68 | + end | |
69 | + | |
70 | +For each request, it first checkes if the "controller/action.format" file is | |
71 | +available (for example "projects/create.xml") and if it's not, it checks if | |
72 | +the resource respond to :to_format (in this case, :to_xml). Otherwise returns 404. | |
73 | + | |
74 | +Another option is to specify which actions the controller will inherit from | |
75 | +the InheritedResources::Base: | |
76 | + | |
77 | + class ProjectsController < InheritedResources::Base | |
78 | + actions :index, :show, :new, :create | |
79 | + end | |
80 | + | |
81 | +Or: | |
82 | + | |
83 | + class ProjectsController < InheritedResources::Base | |
84 | + actions :all, :except => [ :edit, :update, :destroy ] | |
85 | + end | |
86 | + | |
87 | +In your views, you will get the following helpers: | |
88 | + | |
89 | + resource #=> @project | |
90 | + collection #=> @projects | |
91 | + resource_class #=> Project | |
92 | + | |
93 | +As you might expect, collection (@projects instance variable) is only available | |
94 | +on index actions. | |
95 | + | |
96 | +If for some reason you cannot inherit from InheritedResources::Base, you can | |
97 | +call inherit_resources or resource_controller in your controller class scope: | |
98 | + | |
99 | + class AccountsController < ApplicationController | |
100 | + inherit_resources # or resource_controller | |
101 | + end | |
102 | + | |
103 | +Overwriting defaults | |
104 | +-------------------- | |
105 | + | |
106 | +Whenever you inherit from InheritedResources, several defaults are assumed. | |
107 | +For example you can have an AccountsController to account management while the | |
108 | +resource is an User: | |
109 | + | |
110 | + class AccountsController < InheritedResources::Base | |
111 | + defaults :resource_class => User, :collection_name, 'users', :instance_name => 'user' | |
112 | + end | |
113 | + | |
114 | +In the case above, in your views you will have @users and @user variables, but | |
115 | +the routes used will still be accounts_url and account_url. If you plan also to | |
116 | +change the routes, you can use :route_collection_name and :route_instance_name. | |
117 | + | |
118 | +Namespaced controllers work out of the box, but if you need to specify a | |
119 | +different route prefix, you can do the following: | |
120 | + | |
121 | + class Administrators::PeopleController < InheritedResources::Base | |
122 | + defaults :route_prefix => 'admin' | |
123 | + end | |
124 | + | |
125 | +Then your named routes will be: 'admin_people_url', 'admin_person_url' instead | |
126 | +of 'administrators_people_url' and 'administrators_person_url'. | |
127 | + | |
128 | +If you want to customize how resources are retrieved you can overwrite | |
129 | +collection and resource methods. The first is called on index action and the | |
130 | +second on all other actions. Let's suppose you want to add pagination to your | |
131 | +projects collection: | |
132 | + | |
133 | + class ProjectsController < InheritedResources::Base | |
134 | + protected | |
135 | + def collection | |
136 | + @projects ||= end_of_association_chain.paginate(params[:page]).all | |
137 | + end | |
138 | + end | |
139 | + | |
140 | +The end_of_association_chain returns your resource after nesting all associations | |
141 | +and scopes (more about this below). | |
142 | + | |
143 | +InheritedResources also introduces another method called begin_of_association_chain. | |
144 | +It's mostly used when you want to create resources based on the @current_user and | |
145 | +you have urls like "account/projects". In such cases, you have to do | |
146 | +@current_user.projects.find or @current_user.projects.build in your actions. | |
147 | + | |
148 | +You can deal with it just doing: | |
149 | + | |
150 | + class ProjectsController < InheritedResources::Base | |
151 | + protected | |
152 | + def begin_of_association_chain | |
153 | + @current_user | |
154 | + end | |
155 | + end | |
156 | + | |
157 | +Overwriting actions | |
158 | +------------------- | |
159 | + | |
160 | +Let's suppose that after destroying a project you want to redirect to your | |
161 | +root url instead of redirecting to projects url. You just have to do: | |
162 | + | |
163 | + class ProjectsController < InheritedResources::Base | |
164 | + def destroy | |
165 | + super do |format| | |
166 | + format.html { redirect_to root_url } | |
167 | + end | |
168 | + end | |
169 | + end | |
170 | + | |
171 | +You are opening your action and giving the parent action a new behavior. No | |
172 | +tricks, no DSL, just Ruby. | |
173 | + | |
174 | +On the other hand, I have to agree that calling super is not very readable. | |
175 | +That's why all methods have aliases. So this is equivalent: | |
176 | + | |
177 | + class ProjectsController < InheritedResources::Base | |
178 | + def destroy | |
179 | + destroy! do |format| | |
180 | + format.html { redirect_to root_url } | |
181 | + end | |
182 | + end | |
183 | + end | |
184 | + | |
185 | +Even more, since most of the times when you change a create, update or destroy | |
186 | +action is because you want to to change to where it redirects, a shortcut is | |
187 | +provided. So you can do: | |
188 | + | |
189 | + class ProjectsController < InheritedResources::Base | |
190 | + def destroy | |
191 | + destroy!{ root_url } | |
192 | + end | |
193 | + end | |
194 | + | |
195 | +Now let's suppose that before create a project you have to do something special | |
196 | +but you don't want to create a before filter for it: | |
197 | + | |
198 | + class ProjectsController < InheritedResources::Base | |
199 | + def create | |
200 | + @project = Project.new(params[:project]) | |
201 | + @project.something_special! | |
202 | + create! | |
203 | + end | |
204 | + end | |
205 | + | |
206 | +Yes, that simple! The nice part is since you already set the instance variable | |
207 | +@project, it will not build a project again. | |
208 | + | |
209 | +Before we finish this topic, we should talk about one more thing: "success/failure | |
210 | +blocks". Let's suppose that when we update our project, in case of failure, we | |
211 | +want to redirect to the project url instead of re-rendering the edit template. | |
212 | + | |
213 | +Our first attempt to do this would be: | |
214 | + | |
215 | + class ProjectsController < InheritedResources::Base | |
216 | + def update | |
217 | + update! do |format| | |
218 | + unless @project.errors.empty? # failure | |
219 | + format.html { redirect_to project_url(@project) } | |
220 | + end | |
221 | + end | |
222 | + end | |
223 | + end | |
224 | + | |
225 | +Looks to verbose, right? We can actually do: | |
226 | + | |
227 | + class ProjectsController < InheritedResources::Base | |
228 | + def update | |
229 | + update! do |success, failure| | |
230 | + failure.html { redirect_to project_url(@project) } | |
231 | + end | |
232 | + end | |
233 | + end | |
234 | + | |
235 | +Much better! So explaining everything: when you give a block which expects one | |
236 | +argument it will be executed in both scenarios: success and failure. But If you | |
237 | +give a block that expects two arguments, the first will be executed only in | |
238 | +success scenarios and the second in failure scenarios. You keep everything | |
239 | +clean and organized inside the same action. | |
240 | + | |
241 | +Flash messages and I18n | |
242 | +----------------------- | |
243 | + | |
244 | +Flash messages are powered by I18n api. It checks for messages in the following | |
245 | +order: | |
246 | + | |
247 | + flash.controller_name.action_name.status | |
248 | + flash.actions.action_name.status | |
249 | + | |
250 | +If none is available, a default message in english set. In a create action | |
251 | +on projects controller, it will search for: | |
252 | + | |
253 | + flash.projects.create.status | |
254 | + flash.actions.create.status | |
255 | + | |
256 | +The status can be :notice (when the object can be created, updated | |
257 | +or destroyed with success) or :error (when the objecy cannot be created | |
258 | +or updated). | |
259 | + | |
260 | +Those messages are interpolated by using the resource class human name, which | |
261 | +is also localized and it means you can set: | |
262 | + | |
263 | + flash: | |
264 | + actions: | |
265 | + create: | |
266 | + notice: "Hooray! {{resource_name}} was successfully created!" | |
267 | + | |
268 | +It will replace {{resource_name}} by the human name of the resource class, | |
269 | +which is "Project" in this case. | |
270 | + | |
271 | +But sometimes, flash messages are not that simple. Sometimes you want to say | |
272 | +the title of the project while updating a project. Well, that's easy also: | |
273 | + | |
274 | + flash: | |
275 | + projects: | |
276 | + update: | |
277 | + notice: "Hooray! The project "{{project_title}}" was updated!" | |
278 | + | |
279 | +Since :project_title is not available for interpolation by default, you have | |
280 | +to overwrite interpolation_options. | |
281 | + | |
282 | + def interpolation_options | |
283 | + { :project_title => @project.title } | |
284 | + end | |
285 | + | |
286 | +Then you will finally have: | |
287 | + | |
288 | + "Hooray! The project "Plataforma" was updated!" | |
289 | + | |
290 | +By default, resource name is capitalized. If you want to make it lower case, you | |
291 | +can add to your application controller: | |
292 | + | |
293 | + def interpolation_options | |
294 | + { :resource_name => resource_class.human_name.downcase } | |
295 | + end | |
296 | + | |
297 | +Finally, if your controller is namespaced, for example Admin::ProjectsController, | |
298 | +the messages will be checked in the following order: | |
299 | + | |
300 | + flash.admin.projects.create.notice | |
301 | + flash.admin.actions.create.notice | |
302 | + flash.projects.create.notice | |
303 | + flash.actions.create.notice | |
304 | + | |
305 | +Has Scope | |
306 | +--------- | |
307 | + | |
308 | +InheritedResources tries to integrate nicely with your model. In order to do so, | |
309 | +it also is named_scope fluent. Let's suppose our Project model with the scopes: | |
310 | + | |
311 | + class ProjectsController < ActiveRecord::Base | |
312 | + named_scope :featured, :conditions => { :featured => true } | |
313 | + named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } } | |
314 | + named_scope :limit, proc{|limit| :limit => limit.to_i } | |
315 | + end | |
316 | + | |
317 | +Your controller: | |
318 | + | |
319 | + class ProjectsController < InheritedResources::Base | |
320 | + has_scope :featured, :boolean => true, :only => :index | |
321 | + has_scope :by_methodology | |
322 | + has_scope :limit, :default => 10 | |
323 | + end | |
324 | + | |
325 | +Then for each request: | |
326 | + | |
327 | + /projects | |
328 | + #=> acts like a normal request, but returning 10 projects | |
329 | + | |
330 | + /projects?featured=true | |
331 | + #=> calls the featured named scope and bring 10 featured projects | |
332 | + | |
333 | + /projects?featured=true&by_methodology=agile&limit=20 | |
334 | + #=> brings 20 featured projects with methodology agile | |
335 | + | |
336 | +You can retrieve the current scopes in use with :current_scopes method. | |
337 | +In the last case, it would return: | |
338 | + | |
339 | + { :featured => "true", :by_methodology => "agile", :limit => "20" } | |
340 | + | |
341 | +Finally, let's suppose you store on the session how many projects the user sees | |
342 | +per page. In such cases, you can give a proc as default value: | |
343 | + | |
344 | + has_scope :limit, :default => proc{|c| c.session[:limit] || 10 } | |
345 | + | |
346 | +Belongs to | |
347 | +---------- | |
348 | + | |
349 | +Finally, our Projects are going to get some Tasks. Then you create a | |
350 | +TasksController and do: | |
351 | + | |
352 | + class TasksController < InheritedResources::Base | |
353 | + belongs_to :project | |
354 | + end | |
355 | + | |
356 | +belongs_to accepts several options to be able to configure the association. | |
357 | +For example, if you want urls like /projects/:project_title/tasks, you can | |
358 | +customize how InheritedResources find your projects: | |
359 | + | |
360 | + class TasksController < InheritedResources::Base | |
361 | + belongs_to :project, :finder => :find_by_title!, :param => :project_title | |
362 | + end | |
363 | + | |
364 | +It also accepts :route_name, :parent_class and :instance_name as options. | |
365 | +Check the lib/inherited_resources/class_methods.rb for more. | |
366 | + | |
367 | +Nested belongs to | |
368 | +----------------- | |
369 | + | |
370 | +Now, our Tasks get some Comments and you need to nest even deeper. Good | |
371 | +practices says that you should never nest more than two resources, but sometimes | |
372 | +you have to for security reasons. So this is an example of how you can do it: | |
373 | + | |
374 | + class CommentsController < InheritedResources::Base | |
375 | + nested_belongs_to :project, :task | |
376 | + end | |
377 | + | |
378 | +If you need to configure any of these belongs to, you can nested them using blocks: | |
379 | + | |
380 | + class CommentsController < InheritedResources::Base | |
381 | + belongs_to :project, :finder => :find_by_title!, :param => :project_title do | |
382 | + belongs_to :task | |
383 | + end | |
384 | + end | |
385 | + | |
386 | +Warning: calling several belongs_to is the same as nesting them: | |
387 | + | |
388 | + class CommentsConroller < InheritedResources::Base | |
389 | + belongs_to :project | |
390 | + belongs_to :task | |
391 | + end | |
392 | + | |
393 | +In other words, the code above is the same as calling nested_belongs_to. | |
394 | + | |
395 | +Polymorphic belongs to | |
396 | +---------------------- | |
397 | + | |
398 | +We can go even further. Let's suppose our Projects can now have Files, Messages | |
399 | +and Tasks, and they are all commentable. In this case, the best solution is to | |
400 | +use polymorphism: | |
401 | + | |
402 | + class CommentsController < InheritedResources::Base | |
403 | + belongs_to :task, :file, :message, :polymorphic => true | |
404 | + # polymorphic_belongs_to :task, :file, :message | |
405 | + end | |
406 | + | |
407 | +You can even use it with nested resources: | |
408 | + | |
409 | + class CommentsController < InheritedResources::Base | |
410 | + belongs_to :project do | |
411 | + belongs_to :task, :file, :message, :polymorphic => true | |
412 | + end | |
413 | + end | |
414 | + | |
415 | +The url in such cases can be: | |
416 | + | |
417 | + /project/1/task/13/comments | |
418 | + /project/1/file/11/comments | |
419 | + /project/1/message/9/comments | |
420 | + | |
421 | +When using polymorphic associations, you get some free helpers: | |
422 | + | |
423 | + parent? #=> true | |
424 | + parent_type #=> :task | |
425 | + parent_class #=> Task | |
426 | + parent #=> @task | |
427 | + | |
428 | +Optional belongs to | |
429 | +------------------- | |
430 | + | |
431 | +Later you decide to create a view to show all comments, independent if they belong | |
432 | +to a task, file or message. You can reuse your polymorphic controller just doing: | |
433 | + | |
434 | + class ProjectsController < InheritedResources::Base | |
435 | + belongs_to :task, :file, :message, :optional => true | |
436 | + # optional_belongs_to :task, :file, :message | |
437 | + end | |
438 | + | |
439 | +This will handle all those urls properly: | |
440 | + | |
441 | + /comment/1 | |
442 | + /tasks/2/comment/5 | |
443 | + /files/10/comment/3 | |
444 | + /messages/13/comment/11 | |
445 | + | |
446 | +This is treated as a special type of polymorphic associations, thus all helpers | |
447 | +are available. As you expect, when no parent is found, the helpers return: | |
448 | + | |
449 | + parent? #=> false | |
450 | + parent_type #=> nil | |
451 | + parent_class #=> nil | |
452 | + parent #=> nil | |
453 | + | |
454 | +Singletons | |
455 | +---------- | |
456 | + | |
457 | +Now we are going to add manager to projects. We say that Manager is a singleton | |
458 | +resource because a Project has just one manager. You should declare it as | |
459 | +has_one (or resource) in your routes. | |
460 | + | |
461 | +To declare an association as singleton, you just have to give the :singleton | |
462 | +option. | |
463 | + | |
464 | + class ManagersController < InheritedResources::Base | |
465 | + belongs_to :project, :singleton => true | |
466 | + # singleton_belongs_to :project | |
467 | + end | |
468 | + | |
469 | +It will deal with everything again and hide the action :index from you. | |
470 | + | |
471 | +URL Helpers | |
472 | +----------- | |
473 | + | |
474 | +When you use InheritedResources it creates some URL helpers. | |
475 | +And they handle everything for you. :) | |
476 | + | |
477 | + # /posts/1/comments | |
478 | + resource_url # => /posts/1/comments/#{@comment.to_param} | |
479 | + resource_url(comment) # => /posts/1/comments/#{comment.to_param} | |
480 | + new_resource_url # => /posts/1/comments/new | |
481 | + edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit | |
482 | + edit_resource_url(comment) #=> /posts/1/comments/#{comment.to_param}/edit | |
483 | + collection_url # => /posts/1/comments | |
484 | + | |
485 | + # /projects/1/tasks | |
486 | + resource_url # => /projects/1/tasks/#{@task.to_param} | |
487 | + resource_url(task) # => /projects/1/tasks/#{task.to_param} | |
488 | + new_resource_url # => /projects/1/tasks/new | |
489 | + edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit | |
490 | + edit_resource_url(task) # => /projects/1/tasks/#{task.to_param}/edit | |
491 | + collection_url # => /projects/1/tasks | |
492 | + | |
493 | + # /users | |
494 | + resource_url # => /users/#{@user.to_param} | |
495 | + resource_url(user) # => /users/#{user.to_param} | |
496 | + new_resource_url # => /users/new | |
497 | + edit_resource_url # => /users/#{@user.to_param}/edit | |
498 | + edit_resource_url(user) # => /users/#{user.to_param}/edit | |
499 | + collection_url # => /users | |
500 | + | |
501 | +Those urls helpers also accepts a hash as options, just as in named routes. | |
502 | + | |
503 | + # /projects/1/tasks | |
504 | + collection_url(:page => 1, :limit => 10) #=> /projects/1/tasks?page=1&limit=10 | |
505 | + | |
506 | +Another nice thing is that those urls are not guessed during runtime. They are | |
507 | +all created when your application is loaded (except for polymorphic | |
508 | +associations, that relies on Rails polymorphic_url). | |
509 | + | |
510 | +Bugs and Feedback | |
511 | +----------------- | |
512 | + | |
513 | +If you discover any bugs, please send an e-mail to jose.valim@gmail.com | |
514 | +If you just want to give some positive feedback or drop a line, that's fine too! | |
515 | + | |
516 | +Copyright (c) 2009 José Valim | |
517 | +http://josevalim.blogspot.com/ | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/Rakefile
0 → 100644
... | ... | @@ -0,0 +1,35 @@ |
1 | +require 'rake' | |
2 | +require 'rake/testtask' | |
3 | +require 'rake/rdoctask' | |
4 | + | |
5 | +begin | |
6 | + require 'jeweler' | |
7 | + Jeweler::Tasks.new do |s| | |
8 | + s.name = "inherited_resources" | |
9 | + s.rubyforge_project = "inherited_resources" | |
10 | + s.summary = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important." | |
11 | + s.email = "jose.valim@gmail.com" | |
12 | + s.homepage = "http://github.com/josevalim/inherited_resources" | |
13 | + s.description = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important." | |
14 | + s.authors = ['José Valim'] | |
15 | + s.files = FileList["[A-Z]*", "{lib}/**/*"] | |
16 | + end | |
17 | +rescue LoadError | |
18 | + puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" | |
19 | +end | |
20 | + | |
21 | +desc 'Run tests for InheritedResources.' | |
22 | +Rake::TestTask.new(:test) do |t| | |
23 | + t.pattern = 'test/**/*_test.rb' | |
24 | + t.verbose = true | |
25 | +end | |
26 | + | |
27 | +desc 'Generate documentation for InheritedResources.' | |
28 | +Rake::RDocTask.new(:rdoc) do |rdoc| | |
29 | + rdoc.rdoc_dir = 'rdoc' | |
30 | + rdoc.title = 'InheritedResources' | |
31 | + rdoc.options << '--line-numbers' << '--inline-source' | |
32 | + rdoc.rdoc_files.include('README') | |
33 | + rdoc.rdoc_files.include('MIT-LICENSE') | |
34 | + rdoc.rdoc_files.include('lib/**/*.rb') | |
35 | +end | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +0.8.5 | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources.rb
0 → 100644
... | ... | @@ -0,0 +1,18 @@ |
1 | +# respond_to is the only file that should be loaded before hand. All others | |
2 | +# are loaded on demand. | |
3 | +# | |
4 | +require File.join(File.dirname(__FILE__), 'inherited_resources', 'respond_to') | |
5 | + | |
6 | +module InheritedResources; end | |
7 | + | |
8 | +class ActionController::Base | |
9 | + # If you cannot inherit from InheritedResources::Base you can call | |
10 | + # inherit_resource in your controller to have all the required modules and | |
11 | + # funcionality included. | |
12 | + # | |
13 | + def self.inherit_resources | |
14 | + InheritedResources::Base.inherit_resources(self) | |
15 | + initialize_resources_class_accessors! | |
16 | + create_resources_url_helpers! | |
17 | + end | |
18 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/actions.rb
0 → 100644
... | ... | @@ -0,0 +1,96 @@ |
1 | +module InheritedResources | |
2 | + RESOURCES_ACTIONS = [ :index, :show, :new, :edit, :create, :update, :destroy ] unless self.const_defined?(:RESOURCES_ACTIONS) | |
3 | + | |
4 | + # Holds all default actions for InheritedResouces. | |
5 | + module Actions | |
6 | + | |
7 | + # GET /resources | |
8 | + def index(&block) | |
9 | + respond_to(:with => collection, &block) | |
10 | + end | |
11 | + alias :index! :index | |
12 | + | |
13 | + # GET /resources/1 | |
14 | + def show(&block) | |
15 | + respond_to(:with => resource, &block) | |
16 | + end | |
17 | + alias :show! :show | |
18 | + | |
19 | + # GET /resources/new | |
20 | + def new(&block) | |
21 | + respond_to(:with => build_resource, &block) | |
22 | + end | |
23 | + alias :new! :new | |
24 | + | |
25 | + # GET /resources/1/edit | |
26 | + def edit(&block) | |
27 | + respond_to(:with => resource, &block) | |
28 | + end | |
29 | + alias :edit! :edit | |
30 | + | |
31 | + # POST /resources | |
32 | + def create(&block) | |
33 | + object = build_resource | |
34 | + respond_block, redirect_block = select_block_by_arity(block) | |
35 | + | |
36 | + if object.save | |
37 | + set_flash_message!(:notice, '{{resource_name}} was successfully created.') | |
38 | + options = { :with => object, :status => :created, :location => (resource_url rescue nil) } | |
39 | + | |
40 | + respond_to_with_dual_blocks(true, respond_block, options) do |format| | |
41 | + format.html { redirect_to(redirect_block ? redirect_block.call : resource_url) } | |
42 | + end | |
43 | + else | |
44 | + set_flash_message!(:error) | |
45 | + options = { :with => object.errors, :status => :unprocessable_entity } | |
46 | + | |
47 | + respond_to_with_dual_blocks(false, respond_block, options) do |format| | |
48 | + format.html { render :action => 'new' } | |
49 | + end | |
50 | + end | |
51 | + end | |
52 | + alias :create! :create | |
53 | + | |
54 | + # PUT /resources/1 | |
55 | + def update(&block) | |
56 | + object = resource | |
57 | + respond_block, redirect_block = select_block_by_arity(block) | |
58 | + | |
59 | + if object.update_attributes(params[resource_instance_name]) | |
60 | + set_flash_message!(:notice, '{{resource_name}} was successfully updated.') | |
61 | + | |
62 | + respond_to_with_dual_blocks(true, block) do |format| | |
63 | + format.html { redirect_to(redirect_block ? redirect_block.call : resource_url) } | |
64 | + format.all { head :ok } | |
65 | + end | |
66 | + else | |
67 | + set_flash_message!(:error) | |
68 | + | |
69 | + options = { :with => object.errors, :status => :unprocessable_entity } | |
70 | + | |
71 | + respond_to_with_dual_blocks(false, block, options) do |format| | |
72 | + format.html { render :action => 'edit' } | |
73 | + end | |
74 | + end | |
75 | + end | |
76 | + alias :update! :update | |
77 | + | |
78 | + # DELETE /resources/1 | |
79 | + def destroy(&block) | |
80 | + resource.destroy | |
81 | + respond_block, redirect_block = select_block_by_arity(block) | |
82 | + | |
83 | + set_flash_message!(:notice, '{{resource_name}} was successfully destroyed.') | |
84 | + | |
85 | + respond_to_with_dual_blocks(nil, respond_block) do |format| | |
86 | + format.html { redirect_to(redirect_block ? redirect_block.call : collection_url) } | |
87 | + format.all { head :ok } | |
88 | + end | |
89 | + end | |
90 | + alias :destroy! :destroy | |
91 | + | |
92 | + # Make aliases protected | |
93 | + protected :index!, :show!, :new!, :create!, :edit!, :update!, :destroy! | |
94 | + | |
95 | + end | |
96 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/base.rb
0 → 100644
... | ... | @@ -0,0 +1,39 @@ |
1 | +module InheritedResources | |
2 | + # = Base | |
3 | + # | |
4 | + # This is the base class that holds all actions. If you see the code for each | |
5 | + # action, they are quite similar to Rails default scaffold. | |
6 | + # | |
7 | + # To change your base behavior, you can overwrite your actions and call super, | |
8 | + # call <tt>default</tt> class method, call <<tt>actions</tt> class method | |
9 | + # or overwrite some helpers in the base_helpers.rb file. | |
10 | + # | |
11 | + class Base < ::ApplicationController | |
12 | + unloadable | |
13 | + | |
14 | + # Overwrite inherit_resources to add specific InheritedResources behavior. | |
15 | + # | |
16 | + def self.inherit_resources(base) | |
17 | + base.class_eval do | |
18 | + include InheritedResources::Actions | |
19 | + include InheritedResources::BaseHelpers | |
20 | + extend InheritedResources::ClassMethods | |
21 | + extend InheritedResources::UrlHelpers | |
22 | + | |
23 | + helper_method :collection_url, :collection_path, :resource_url, :resource_path, | |
24 | + :new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path, | |
25 | + :resource, :collection, :resource_class | |
26 | + | |
27 | + base.with_options :instance_writer => false do |c| | |
28 | + c.class_inheritable_accessor :resource_class | |
29 | + c.class_inheritable_array :parents_symbols | |
30 | + c.class_inheritable_hash :resources_configuration, :scopes_configuration | |
31 | + end | |
32 | + | |
33 | + protected :resource_class, :parents_symbols, :resources_configuration, :scopes_configuration | |
34 | + end | |
35 | + end | |
36 | + | |
37 | + inherit_resources(self) | |
38 | + end | |
39 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/base_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,329 @@ |
1 | +# Whenever base is required load the dumb responder since it's used inside actions. | |
2 | +require File.dirname(__FILE__) + '/dumb_responder.rb' | |
3 | + | |
4 | +module InheritedResources | |
5 | + # Base helpers for InheritedResource work. Some methods here can be overwriten | |
6 | + # and you will need to do that to customize your controllers from time to time. | |
7 | + # | |
8 | + module BaseHelpers | |
9 | + | |
10 | + protected | |
11 | + | |
12 | + # This is how the collection is loaded. | |
13 | + # | |
14 | + # You might want to overwrite this method if you want to add pagination | |
15 | + # for example. When you do that, don't forget to cache the result in an | |
16 | + # instance_variable: | |
17 | + # | |
18 | + # def collection | |
19 | + # @projects ||= end_of_association_chain.paginate(params[:page]).all | |
20 | + # end | |
21 | + # | |
22 | + def collection | |
23 | + get_collection_ivar || set_collection_ivar(end_of_association_chain.find(:all)) | |
24 | + end | |
25 | + | |
26 | + # This is how the resource is loaded. | |
27 | + # | |
28 | + # You might want to overwrite this method when you are using permalink. | |
29 | + # When you do that, don't forget to cache the result in an | |
30 | + # instance_variable: | |
31 | + # | |
32 | + # def resource | |
33 | + # @project ||= end_of_association_chain.find_by_permalink!(params[:id]) | |
34 | + # end | |
35 | + # | |
36 | + # You also might want to add the exclamation mark at the end of the method | |
37 | + # because it will raise a 404 if nothing can be found. Otherwise it will | |
38 | + # probably render a 500 error message. | |
39 | + # | |
40 | + def resource | |
41 | + get_resource_ivar || set_resource_ivar(end_of_association_chain.find(params[:id])) | |
42 | + end | |
43 | + | |
44 | + # This method is responsable for building the object on :new and :create | |
45 | + # methods. If you overwrite it, don't forget to cache the result in an | |
46 | + # instance variable. | |
47 | + # | |
48 | + def build_resource | |
49 | + get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, params[resource_instance_name])) | |
50 | + end | |
51 | + | |
52 | + # This class allows you to set a instance variable to begin your | |
53 | + # association chain. For example, usually your projects belongs to users | |
54 | + # and that means that they belong to the current logged in user. So you | |
55 | + # could do this: | |
56 | + # | |
57 | + # def begin_of_association_chain | |
58 | + # @current_user | |
59 | + # end | |
60 | + # | |
61 | + # So every time we instantiate a project, we will do: | |
62 | + # | |
63 | + # @current_user.projects.build(params[:project]) | |
64 | + # @current_user.projects.find(params[:id]) | |
65 | + # | |
66 | + # The variable set in begin_of_association_chain is not sent when building | |
67 | + # urls, so this is never going to happen when calling resource_url: | |
68 | + # | |
69 | + # project_url(@current_user, @project) | |
70 | + # | |
71 | + # If the user actually scopes the url, you should use belongs_to method | |
72 | + # and declare that projects belong to user. | |
73 | + # | |
74 | + def begin_of_association_chain | |
75 | + nil | |
76 | + end | |
77 | + | |
78 | + # Returns if the controller has a parent. When only base helpers are loaded, | |
79 | + # it's always false and should not be overwriten. | |
80 | + # | |
81 | + def parent? | |
82 | + false | |
83 | + end | |
84 | + | |
85 | + # Overwrite this method to provide other interpolation options when | |
86 | + # the flash message is going to be set. | |
87 | + # | |
88 | + # def interpolation_options | |
89 | + # { } | |
90 | + # end | |
91 | + | |
92 | + private | |
93 | + | |
94 | + # Fast accessor to resource_collection_name | |
95 | + # | |
96 | + def resource_collection_name #:nodoc: | |
97 | + self.resources_configuration[:self][:collection_name] | |
98 | + end | |
99 | + | |
100 | + # Fast accessor to resource_instance_name | |
101 | + # | |
102 | + def resource_instance_name #:nodoc: | |
103 | + self.resources_configuration[:self][:instance_name] | |
104 | + end | |
105 | + | |
106 | + # This methods gets your begin_of_association_chain, join it with your | |
107 | + # parents chain and returns the scoped association. | |
108 | + # | |
109 | + def end_of_association_chain #:nodoc: | |
110 | + chain = symbols_for_association_chain.inject(begin_of_association_chain) do |chain, symbol| | |
111 | + evaluate_parent(symbol, resources_configuration[symbol], chain) | |
112 | + end | |
113 | + | |
114 | + if chain | |
115 | + if method_for_association_chain | |
116 | + apply_scope_to(chain.send(method_for_association_chain)) | |
117 | + else | |
118 | + # This only happens when we specify begin_of_association_chain in | |
119 | + # a singletion controller without parents. In this case, the chain | |
120 | + # is exactly the begin_of_association_chain which is already an | |
121 | + # instance and then not scopable. | |
122 | + chain | |
123 | + end | |
124 | + else | |
125 | + apply_scope_to(resource_class) | |
126 | + end | |
127 | + end | |
128 | + | |
129 | + # Returns the appropriated method to build the resource. | |
130 | + # | |
131 | + def method_for_build #:nodoc: | |
132 | + (begin_of_association_chain || parent?) ? method_for_association_build : :new | |
133 | + end | |
134 | + | |
135 | + # Returns the name of the method used for build the resource in cases | |
136 | + # where we have a parent. This is overwritten in singleton scenarios. | |
137 | + # | |
138 | + def method_for_association_build | |
139 | + :build | |
140 | + end | |
141 | + | |
142 | + # Returns the name of the method to be called, before returning the end | |
143 | + # of the association chain. This is overwriten by singleton cases | |
144 | + # where no method for association chain is called. | |
145 | + # | |
146 | + def method_for_association_chain #:nodoc: | |
147 | + resource_collection_name | |
148 | + end | |
149 | + | |
150 | + # Get resource ivar based on the current resource controller. | |
151 | + # | |
152 | + def get_resource_ivar #:nodoc: | |
153 | + instance_variable_get("@#{resource_instance_name}") | |
154 | + end | |
155 | + | |
156 | + # Set resource ivar based on the current resource controller. | |
157 | + # | |
158 | + def set_resource_ivar(resource) #:nodoc: | |
159 | + instance_variable_set("@#{resource_instance_name}", resource) | |
160 | + end | |
161 | + | |
162 | + # Get collection ivar based on the current resource controller. | |
163 | + # | |
164 | + def get_collection_ivar #:nodoc: | |
165 | + instance_variable_get("@#{resource_collection_name}") | |
166 | + end | |
167 | + | |
168 | + # Set collection ivar based on the current resource controller. | |
169 | + # | |
170 | + def set_collection_ivar(collection) #:nodoc: | |
171 | + instance_variable_set("@#{resource_collection_name}", collection) | |
172 | + end | |
173 | + | |
174 | + # Helper to set flash messages. It's powered by I18n API. | |
175 | + # It checks for messages in the following order: | |
176 | + # | |
177 | + # flash.controller_name.action_name.status | |
178 | + # flash.actions.action_name.status | |
179 | + # | |
180 | + # If none is available, a default message is set. So, if you have | |
181 | + # a CarsController, create action, it will check for: | |
182 | + # | |
183 | + # flash.cars.create.status | |
184 | + # flash.actions.create.status | |
185 | + # | |
186 | + # The statuses can be :notice (when the object can be created, updated | |
187 | + # or destroyed with success) or :error (when the objecy cannot be created | |
188 | + # or updated). | |
189 | + # | |
190 | + # Those messages are interpolated by using the resource class human name. | |
191 | + # This means you can set: | |
192 | + # | |
193 | + # flash: | |
194 | + # actions: | |
195 | + # create: | |
196 | + # notice: "Hooray! {{resource_name}} was successfully created!" | |
197 | + # | |
198 | + # But sometimes, flash messages are not that simple. Going back | |
199 | + # to cars example, you might want to say the brand of the car when it's | |
200 | + # updated. Well, that's easy also: | |
201 | + # | |
202 | + # flash: | |
203 | + # cars: | |
204 | + # update: | |
205 | + # notice: "Hooray! You just tuned your {{car_brand}}!" | |
206 | + # | |
207 | + # Since :car_name is not available for interpolation by default, you have | |
208 | + # to overwrite interpolation_options. | |
209 | + # | |
210 | + # def interpolation_options | |
211 | + # { :car_brand => @car.brand } | |
212 | + # end | |
213 | + # | |
214 | + # Then you will finally have: | |
215 | + # | |
216 | + # 'Hooray! You just tuned your Aston Martin!' | |
217 | + # | |
218 | + # If your controller is namespaced, for example Admin::CarsController, | |
219 | + # the messages will be checked in the following order: | |
220 | + # | |
221 | + # flash.admin.cars.create.status | |
222 | + # flash.admin.actions.create.status | |
223 | + # flash.cars.create.status | |
224 | + # flash.actions.create.status | |
225 | + # | |
226 | + def set_flash_message!(status, default_message=nil) | |
227 | + return flash[status] = default_message unless defined?(::I18n) | |
228 | + | |
229 | + resource_name = if resource_class | |
230 | + if resource_class.respond_to?(:human_name) | |
231 | + resource_class.human_name | |
232 | + else | |
233 | + resource_class.name.humanize | |
234 | + end | |
235 | + else | |
236 | + "Resource" | |
237 | + end | |
238 | + | |
239 | + given_options = if self.respond_to?(:interpolation_options) | |
240 | + interpolation_options | |
241 | + else | |
242 | + {} | |
243 | + end | |
244 | + | |
245 | + options = { | |
246 | + :default => default_message || '', | |
247 | + :resource_name => resource_name | |
248 | + }.merge(given_options) | |
249 | + | |
250 | + defaults = [] | |
251 | + slices = controller_path.split('/') | |
252 | + | |
253 | + while slices.size > 0 | |
254 | + defaults << :"flash.#{slices.fill(controller_name, -1).join('.')}.#{action_name}.#{status}" | |
255 | + defaults << :"flash.#{slices.fill(:actions, -1).join('.')}.#{action_name}.#{status}" | |
256 | + slices.shift | |
257 | + end | |
258 | + | |
259 | + options[:default] = defaults.push(options[:default]) | |
260 | + options[:default].flatten! | |
261 | + | |
262 | + message = ::I18n.t options[:default].shift, options | |
263 | + flash[status] = message unless message.blank? | |
264 | + end | |
265 | + | |
266 | + # Used to allow to specify success and failure within just one block: | |
267 | + # | |
268 | + # def create | |
269 | + # create! do |success, failure| | |
270 | + # failure.html { redirect_to root_url } | |
271 | + # end | |
272 | + # end | |
273 | + # | |
274 | + def respond_to_with_dual_blocks(success, dual_block, options={}, &block) #:nodoc: | |
275 | + responder = ActionController::MimeResponds::Responder.new(self) | |
276 | + | |
277 | + if dual_block | |
278 | + if dual_block.arity == 2 | |
279 | + dumb_responder = InheritedResources::DumbResponder.new | |
280 | + if success | |
281 | + dual_block.call(responder, dumb_responder) | |
282 | + else | |
283 | + dual_block.call(dumb_responder, responder) | |
284 | + end | |
285 | + else | |
286 | + dual_block.call(responder) | |
287 | + end | |
288 | + | |
289 | + # Try to respond with the block given | |
290 | + responder.respond_except_any | |
291 | + end | |
292 | + | |
293 | + respond_to(options.merge!(:responder => responder, :prioritize => :html), &block) unless performed? | |
294 | + end | |
295 | + | |
296 | + # Hook to apply scopes. By default returns only the target_object given. | |
297 | + # It's extend by HasScopeHelpers. | |
298 | + # | |
299 | + def apply_scope_to(target_object) #:nodoc: | |
300 | + target_object | |
301 | + end | |
302 | + | |
303 | + # Symbols chain in base helpers return nothing. This is later overwriten | |
304 | + # by belongs_to and can be complex in polymorphic cases. | |
305 | + # | |
306 | + def symbols_for_association_chain #:nodoc: | |
307 | + [] | |
308 | + end | |
309 | + | |
310 | + # Holds InheritedResources block structure. It returns two blocks: the first | |
311 | + # is used in respond_to blocks and the second is the redirect_to url. | |
312 | + # | |
313 | + def select_block_by_arity(block) #:nodoc | |
314 | + if block | |
315 | + case block.arity | |
316 | + when 2, 1 | |
317 | + [block, nil] | |
318 | + when 0, -1 | |
319 | + [nil, block] | |
320 | + else | |
321 | + raise ScriptError, "InheritedResources does not know how to handle blocks with arity #{block.arity}" | |
322 | + end | |
323 | + else | |
324 | + [nil, nil] | |
325 | + end | |
326 | + end | |
327 | + | |
328 | + end | |
329 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/belongs_to_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,89 @@ |
1 | +module InheritedResources | |
2 | + | |
3 | + # = belongs_to | |
4 | + # | |
5 | + # Let's suppose that we have some tasks that belongs to projects. To specify | |
6 | + # this assoication in your controllers, just do: | |
7 | + # | |
8 | + # class TasksController < InheritedResources::Base | |
9 | + # belongs_to :project | |
10 | + # end | |
11 | + # | |
12 | + # belongs_to accepts several options to be able to configure the association. | |
13 | + # For example, if you want urls like /projects/:project_title/tasks, you | |
14 | + # can customize how InheritedResources find your projects: | |
15 | + # | |
16 | + # class TasksController < InheritedResources::Base | |
17 | + # belongs_to :project, :finder => :find_by_title!, :param => :project_title | |
18 | + # end | |
19 | + # | |
20 | + # It also accepts :route_name, :parent_class and :instance_name as options. | |
21 | + # Check the lib/inherited_resources/class_methods.rb for more. | |
22 | + # | |
23 | + # = nested_belongs_to | |
24 | + # | |
25 | + # Now, our Tasks get some Comments and you need to nest even deeper. Good | |
26 | + # practices says that you should never nest more than two resources, but sometimes | |
27 | + # you have to for security reasons. So this is an example of how you can do it: | |
28 | + # | |
29 | + # class CommentsController < InheritedResources::Base | |
30 | + # nested_belongs_to :project, :task | |
31 | + # end | |
32 | + # | |
33 | + # If you need to configure any of these belongs to, you can nested them using blocks: | |
34 | + # | |
35 | + # class CommentsController < InheritedResources::Base | |
36 | + # belongs_to :project, :finder => :find_by_title!, :param => :project_title do | |
37 | + # belongs_to :task | |
38 | + # end | |
39 | + # end | |
40 | + # | |
41 | + # Warning: calling several belongs_to is the same as nesting them: | |
42 | + # | |
43 | + # class CommentsController < InheritedResources::Base | |
44 | + # belongs_to :project | |
45 | + # belongs_to :task | |
46 | + # end | |
47 | + # | |
48 | + # In other words, the code above is the same as calling nested_belongs_to. | |
49 | + # | |
50 | + module BelongsToHelpers | |
51 | + | |
52 | + protected | |
53 | + | |
54 | + # Parent is always true when belongs_to is called. | |
55 | + # | |
56 | + def parent? | |
57 | + true | |
58 | + end | |
59 | + | |
60 | + private | |
61 | + | |
62 | + # Evaluate the parent given. This is used to nest parents in the | |
63 | + # association chain. | |
64 | + # | |
65 | + def evaluate_parent(parent_symbol, parent_config, chain = nil) #:nodoc: | |
66 | + instantiated_object = instance_variable_get("@#{parent_config[:instance_name]}") | |
67 | + return instantiated_object if instantiated_object | |
68 | + | |
69 | + parent = if chain | |
70 | + chain.send(parent_config[:collection_name]) | |
71 | + else | |
72 | + parent_config[:parent_class] | |
73 | + end | |
74 | + | |
75 | + parent = parent.send(parent_config[:finder], params[parent_config[:param]]) | |
76 | + | |
77 | + instance_variable_set("@#{parent_config[:instance_name]}", parent) | |
78 | + end | |
79 | + | |
80 | + # Maps parents_symbols to build association chain. In this case, it | |
81 | + # simply return the parent_symbols, however on polymorphic belongs to, | |
82 | + # it has some customization. | |
83 | + # | |
84 | + def symbols_for_association_chain #:nodoc: | |
85 | + parents_symbols | |
86 | + end | |
87 | + | |
88 | + end | |
89 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/class_methods.rb
0 → 100644
... | ... | @@ -0,0 +1,328 @@ |
1 | +module InheritedResources | |
2 | + module ClassMethods | |
3 | + | |
4 | + protected | |
5 | + | |
6 | + # Used to overwrite the default assumptions InheritedResources do. Whenever | |
7 | + # this method is called, it should be on the top of your controller, since | |
8 | + # almost other methods depends on the values given to <<tt>>defaults</tt>. | |
9 | + # | |
10 | + # == Options | |
11 | + # | |
12 | + # * <tt>:resource_class</tt> - The resource class which by default is guessed | |
13 | + # by the controller name. Defaults to Project in | |
14 | + # ProjectsController. | |
15 | + # | |
16 | + # * <tt>:collection_name</tt> - The name of the collection instance variable which | |
17 | + # is set on the index action. Defaults to :projects in | |
18 | + # ProjectsController. | |
19 | + # | |
20 | + # * <tt>:instance_name</tt> - The name of the singular instance variable which | |
21 | + # is set on all actions besides index action. Defaults to | |
22 | + # :project in ProjectsController. | |
23 | + # | |
24 | + # * <tt>:route_collection_name</tt> - The name of the collection route. Defaults to :collection_name. | |
25 | + # | |
26 | + # * <tt>:route_instance_name</tt> - The name of the singular route. Defaults to :instance_name. | |
27 | + # | |
28 | + # * <tt>:route_prefix</tt> - The route prefix which is automically set in namespaced | |
29 | + # controllers. Default to :admin on Admin::ProjectsController. | |
30 | + # | |
31 | + # * <tt>:singleton</tt> - Tells if this controller is singleton or not. | |
32 | + # | |
33 | + def defaults(options) | |
34 | + raise ArgumentError, 'Class method :defaults expects a hash of options.' unless options.is_a? Hash | |
35 | + | |
36 | + options.symbolize_keys! | |
37 | + options.assert_valid_keys(:resource_class, :collection_name, :instance_name, | |
38 | + :class_name, :route_prefix, :route_collection_name, | |
39 | + :route_instance_name, :singleton) | |
40 | + | |
41 | + self.resource_class = options.delete(:resource_class) if options.key?(:resource_class) | |
42 | + self.resource_class = options.delete(:class_name).constantize if options.key?(:class_name) | |
43 | + | |
44 | + acts_as_singleton! if options.delete(:singleton) | |
45 | + | |
46 | + config = self.resources_configuration[:self] | |
47 | + config[:route_prefix] = options.delete(:route_prefix) if options.key?(:route_prefix) | |
48 | + | |
49 | + options.each do |key, value| | |
50 | + config[key] = value.to_sym | |
51 | + end | |
52 | + | |
53 | + create_resources_url_helpers! | |
54 | + end | |
55 | + | |
56 | + # Defines wich actions to keep from the inherited controller. | |
57 | + # Syntax is borrowed from resource_controller. | |
58 | + # | |
59 | + # actions :index, :show, :edit | |
60 | + # actions :all, :except => :index | |
61 | + # | |
62 | + def actions(*actions_to_keep) | |
63 | + raise ArgumentError, 'Wrong number of arguments. You have to provide which actions you want to keep.' if actions_to_keep.empty? | |
64 | + | |
65 | + options = actions_to_keep.extract_options! | |
66 | + actions_to_keep.map!{ |a| a.to_s } | |
67 | + | |
68 | + actions_to_remove = Array(options[:except]) | |
69 | + actions_to_remove.map!{ |a| a.to_s } | |
70 | + | |
71 | + actions_to_remove += RESOURCES_ACTIONS.map{|a| a.to_s } - actions_to_keep unless actions_to_keep.first == 'all' | |
72 | + actions_to_remove.uniq! | |
73 | + | |
74 | + (instance_methods & actions_to_remove).each do |action| | |
75 | + undef_method action, "#{action}!" | |
76 | + end | |
77 | + end | |
78 | + | |
79 | + # Detects params from url and apply as scopes to your classes. | |
80 | + # | |
81 | + # Your model: | |
82 | + # | |
83 | + # class Graduation < ActiveRecord::Base | |
84 | + # named_scope :featured, :conditions => { :featured => true } | |
85 | + # named_scope :by_degree, proc {|degree| { :conditions => { :degree => degree } } } | |
86 | + # end | |
87 | + # | |
88 | + # Your controller: | |
89 | + # | |
90 | + # class GraduationsController < InheritedResources::Base | |
91 | + # has_scope :featured, :boolean => true, :only => :index | |
92 | + # has_scope :by_degree, :only => :index | |
93 | + # end | |
94 | + # | |
95 | + # Then for each request: | |
96 | + # | |
97 | + # /graduations | |
98 | + # #=> acts like a normal request | |
99 | + # | |
100 | + # /graduations?featured=true | |
101 | + # #=> calls the named scope and bring featured graduations | |
102 | + # | |
103 | + # /graduations?featured=true&by_degree=phd | |
104 | + # #=> brings featured graduations with phd degree | |
105 | + # | |
106 | + # You can retrieve the current scopes in use with <tt>current_scopes</tt> | |
107 | + # method. In the last case, it would return: { :featured => "true", :by_degree => "phd" } | |
108 | + # | |
109 | + # == Options | |
110 | + # | |
111 | + # * <tt>:boolean</tt> - When set to true, call the scope only when the params is true or 1, | |
112 | + # and does not send the value as argument. | |
113 | + # | |
114 | + # * <tt>:only</tt> - In each actions the scope is applied. By default is :all. | |
115 | + # | |
116 | + # * <tt>:except</tt> - In each actions the scope is not applied. By default is :none. | |
117 | + # | |
118 | + # * <tt>:key</tt> - The key in the params hash expected to find the scope. | |
119 | + # Defaults to the scope name. | |
120 | + # | |
121 | + # * <tt>:default</tt> - Default value for the scope. Whenever supplied the scope | |
122 | + # is always called. This is useful to add easy pagination! | |
123 | + # | |
124 | + def has_scope(*scopes) | |
125 | + options = scopes.extract_options! | |
126 | + | |
127 | + options.symbolize_keys! | |
128 | + options.assert_valid_keys(:boolean, :key, :only, :except, :default) | |
129 | + | |
130 | + if self.scopes_configuration.empty? | |
131 | + include HasScopeHelpers | |
132 | + helper_method :current_scopes | |
133 | + end | |
134 | + | |
135 | + scopes.each do |scope| | |
136 | + self.scopes_configuration[scope] ||= {} | |
137 | + self.scopes_configuration[scope][:key] = options[:key] || scope | |
138 | + self.scopes_configuration[scope][:only] = Array(options[:only]) | |
139 | + self.scopes_configuration[scope][:except] = Array(options[:except]) | |
140 | + self.scopes_configuration[scope][:boolean] = options[:boolean] if options.key?(:boolean) | |
141 | + self.scopes_configuration[scope][:default] = options[:default] if options.key?(:default) | |
142 | + end | |
143 | + end | |
144 | + | |
145 | + # Defines that this controller belongs to another resource. | |
146 | + # | |
147 | + # belongs_to :projects | |
148 | + # | |
149 | + # == Options | |
150 | + # | |
151 | + # * <tt>:parent_class</tt> - Allows you to specify what is the parent class. | |
152 | + # | |
153 | + # belongs_to :project, :parent_class => AdminProject | |
154 | + # | |
155 | + # * <tt>:class_name</tt> - Also allows you to specify the parent class, but you should | |
156 | + # give a string. Added for ActiveRecord belongs to compatibility. | |
157 | + # | |
158 | + # * <tt>:instance_name</tt> - The instance variable name. By default is the name of the association. | |
159 | + # | |
160 | + # belongs_to :project, :instance_name => :my_project | |
161 | + # | |
162 | + # * <tt>:finder</tt> - Specifies which method should be called to instantiate the parent. | |
163 | + # | |
164 | + # belongs_to :project, :finder => :find_by_title! | |
165 | + # | |
166 | + # This will make your projects be instantiated as: | |
167 | + # | |
168 | + # Project.find_by_title!(params[:project_id]) | |
169 | + # | |
170 | + # Instead of: | |
171 | + # | |
172 | + # Project.find(params[:project_id]) | |
173 | + # | |
174 | + # * <tt>:param</tt> - Allows you to specify params key to retrieve the id. | |
175 | + # Default is :association_id, which in this case is :project_id. | |
176 | + # | |
177 | + # * <tt>:route_name</tt> - Allows you to specify what is the route name in your url | |
178 | + # helper. By default is association name. | |
179 | + # | |
180 | + # * <tt>:collection_name</tt> - Tell how to retrieve the next collection. Let's | |
181 | + # suppose you have Tasks which belongs to Projects | |
182 | + # which belongs to companies. This will do somewhere | |
183 | + # down the road: | |
184 | + # | |
185 | + # @company.projects | |
186 | + # | |
187 | + # But if you want to retrieve instead: | |
188 | + # | |
189 | + # @company.admin_projects | |
190 | + # | |
191 | + # You supply the collection name. | |
192 | + # | |
193 | + # * <tt>:polymorphic</tt> - Tell the association is polymorphic. | |
194 | + # | |
195 | + # * <tt>:singleton</tt> - Tell it's a singleton association. | |
196 | + # | |
197 | + # * <tt>:optional</tt> - Tell the association is optional (it's a special | |
198 | + # type of polymorphic association) | |
199 | + # | |
200 | + def belongs_to(*symbols, &block) | |
201 | + options = symbols.extract_options! | |
202 | + | |
203 | + options.symbolize_keys! | |
204 | + options.assert_valid_keys(:class_name, :parent_class, :instance_name, :param, | |
205 | + :finder, :route_name, :collection_name, :singleton, | |
206 | + :polymorphic, :optional) | |
207 | + | |
208 | + optional = options.delete(:optional) | |
209 | + singleton = options.delete(:singleton) | |
210 | + polymorphic = options.delete(:polymorphic) | |
211 | + | |
212 | + include BelongsToHelpers if self.parents_symbols.empty? | |
213 | + | |
214 | + acts_as_singleton! if singleton | |
215 | + acts_as_polymorphic! if polymorphic || optional | |
216 | + | |
217 | + raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty? | |
218 | + raise ArgumentError, 'You cannot define multiple associations with options: #{options.keys.inspect} to belongs to.' unless symbols.size == 1 || options.empty? | |
219 | + | |
220 | + symbols.each do |symbol| | |
221 | + symbol = symbol.to_sym | |
222 | + | |
223 | + if polymorphic || optional | |
224 | + self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic) | |
225 | + self.resources_configuration[:polymorphic][:symbols] << symbol | |
226 | + self.resources_configuration[:polymorphic][:optional] ||= optional | |
227 | + else | |
228 | + self.parents_symbols << symbol | |
229 | + end | |
230 | + | |
231 | + config = self.resources_configuration[symbol] = {} | |
232 | + config[:parent_class] = options.delete(:parent_class) | |
233 | + config[:parent_class] ||= (options.delete(:class_name) || symbol).to_s.classify.constantize rescue nil | |
234 | + config[:collection_name] = options.delete(:collection_name) || symbol.to_s.pluralize.to_sym | |
235 | + config[:instance_name] = options.delete(:instance_name) || symbol | |
236 | + config[:param] = options.delete(:param) || :"#{symbol}_id" | |
237 | + config[:finder] = options.delete(:finder) || :find | |
238 | + config[:route_name] = options.delete(:route_name) || symbol | |
239 | + end | |
240 | + | |
241 | + if block_given? | |
242 | + class_eval(&block) | |
243 | + else | |
244 | + create_resources_url_helpers! | |
245 | + end | |
246 | + end | |
247 | + alias :nested_belongs_to :belongs_to | |
248 | + | |
249 | + # A quick method to declare polymorphic belongs to. | |
250 | + # | |
251 | + def polymorphic_belongs_to(*symbols, &block) | |
252 | + options = symbols.extract_options! | |
253 | + options.merge!(:polymorphic => true) | |
254 | + belongs_to(*symbols << options, &block) | |
255 | + end | |
256 | + | |
257 | + # A quick method to declare singleton belongs to. | |
258 | + # | |
259 | + def singleton_belongs_to(*symbols, &block) | |
260 | + options = symbols.extract_options! | |
261 | + options.merge!(:singleton => true) | |
262 | + belongs_to(*symbols << options, &block) | |
263 | + end | |
264 | + | |
265 | + # A quick method to declare optional belongs to. | |
266 | + # | |
267 | + def optional_belongs_to(*symbols, &block) | |
268 | + options = symbols.extract_options! | |
269 | + options.merge!(:optional => true) | |
270 | + belongs_to(*symbols << options, &block) | |
271 | + end | |
272 | + | |
273 | + private | |
274 | + | |
275 | + def acts_as_singleton! #:nodoc: | |
276 | + unless self.resources_configuration[:self][:singleton] | |
277 | + self.resources_configuration[:self][:singleton] = true | |
278 | + include SingletonHelpers | |
279 | + actions :all, :except => :index | |
280 | + end | |
281 | + end | |
282 | + | |
283 | + def acts_as_polymorphic! #:nodoc: | |
284 | + unless self.parents_symbols.include?(:polymorphic) | |
285 | + include PolymorphicHelpers | |
286 | + helper_method :parent, :parent_type, :parent_class, :parent? | |
287 | + end | |
288 | + end | |
289 | + | |
290 | + # Initialize resources class accessors and set their default values. | |
291 | + # | |
292 | + def initialize_resources_class_accessors! #:nodoc: | |
293 | + # Initialize resource class | |
294 | + self.resource_class = begin | |
295 | + self.controller_name.classify.constantize | |
296 | + rescue NameError | |
297 | + nil | |
298 | + end | |
299 | + | |
300 | + # Initialize resources configuration hash | |
301 | + self.resources_configuration ||= {} | |
302 | + config = self.resources_configuration[:self] = {} | |
303 | + config[:collection_name] = self.controller_name.to_sym | |
304 | + config[:instance_name] = self.controller_name.singularize.to_sym | |
305 | + | |
306 | + config[:route_collection_name] = config[:collection_name] | |
307 | + config[:route_instance_name] = config[:instance_name] | |
308 | + | |
309 | + # Deal with namespaced controllers | |
310 | + namespaces = self.controller_path.split('/')[0..-2] | |
311 | + config[:route_prefix] = namespaces.join('_') unless namespaces.empty? | |
312 | + | |
313 | + # Initialize polymorphic, singleton, scopes and belongs_to parameters | |
314 | + self.parents_symbols ||= [] | |
315 | + self.scopes_configuration ||= {} | |
316 | + self.resources_configuration[:polymorphic] ||= { :symbols => [], :optional => false } | |
317 | + end | |
318 | + | |
319 | + # Hook called on inheritance. | |
320 | + # | |
321 | + def inherited(base) #:nodoc: | |
322 | + super(base) | |
323 | + base.send :initialize_resources_class_accessors! | |
324 | + base.send :create_resources_url_helpers! | |
325 | + end | |
326 | + | |
327 | + end | |
328 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/dumb_responder.rb
0 → 100644
... | ... | @@ -0,0 +1,20 @@ |
1 | +module InheritedResources | |
2 | + # = Dumb Responder | |
3 | + # | |
4 | + # This responder discards all messages sent to him. | |
5 | + # | |
6 | + class DumbResponder | |
7 | + | |
8 | + instance_methods.each do |m| | |
9 | + undef_method m unless m =~ /^__/ | |
10 | + end | |
11 | + | |
12 | + # This is like a good husband, he will just listen everything that his wife | |
13 | + # says (which is a lot) without complaining. :) | |
14 | + # | |
15 | + def method_missing(*args) | |
16 | + nil | |
17 | + end | |
18 | + | |
19 | + end | |
20 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/has_scope_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,65 @@ |
1 | +module InheritedResources | |
2 | + | |
3 | + # = has_scopes | |
4 | + # | |
5 | + # This module in included in your controller when has_scope is called for the | |
6 | + # first time. | |
7 | + # | |
8 | + module HasScopeHelpers | |
9 | + TRUE_VALUES = ["true", true, "1", 1] unless self.const_defined?(:TRUE_VALUES) | |
10 | + | |
11 | + protected | |
12 | + | |
13 | + # Overwrites apply to scope to implement default scope logic. | |
14 | + # | |
15 | + def apply_scope_to(target_object) #:nodoc: | |
16 | + @current_scopes ||= {} | |
17 | + | |
18 | + self.scopes_configuration.each do |scope, options| | |
19 | + next unless apply_scope_to_action?(options) | |
20 | + key = options[:key] | |
21 | + | |
22 | + if params.key?(key) | |
23 | + value, call_scope = params[key], true | |
24 | + elsif options.key?(:default) | |
25 | + value, call_scope = options[:default], true | |
26 | + value = value.call(self) if value.is_a?(Proc) | |
27 | + end | |
28 | + | |
29 | + if call_scope | |
30 | + @current_scopes[key] = value | |
31 | + | |
32 | + if options[:boolean] | |
33 | + target_object = target_object.send(scope) if TRUE_VALUES.include?(value) | |
34 | + else | |
35 | + target_object = target_object.send(scope, value) | |
36 | + end | |
37 | + end | |
38 | + end | |
39 | + | |
40 | + target_object | |
41 | + end | |
42 | + | |
43 | + # Given an options with :only and :except arrays, check if the scope | |
44 | + # can be performed in the current action. | |
45 | + # | |
46 | + def apply_scope_to_action?(options) #:nodoc: | |
47 | + if options[:only].empty? | |
48 | + if options[:except].empty? | |
49 | + true | |
50 | + else | |
51 | + !options[:except].include?(action_name.to_sym) | |
52 | + end | |
53 | + else | |
54 | + options[:only].include?(action_name.to_sym) | |
55 | + end | |
56 | + end | |
57 | + | |
58 | + # Returns the scopes used in this action. | |
59 | + # | |
60 | + def current_scopes | |
61 | + @current_scopes || {} | |
62 | + end | |
63 | + | |
64 | + end | |
65 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/polymorphic_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,156 @@ |
1 | +module InheritedResources | |
2 | + | |
3 | + # = polymorphic associations | |
4 | + # | |
5 | + # In some cases you have a resource that belongs to two different resources | |
6 | + # but not at the same time. For example, let's suppose you have File, Message | |
7 | + # and Task as resources and they are all commentable. | |
8 | + # | |
9 | + # Polymorphic associations allows you to create just one controller that will | |
10 | + # deal with each case. | |
11 | + # | |
12 | + # class Comment < InheritedResources::Base | |
13 | + # belongs_to :file, :message, :task, :polymorphic => true | |
14 | + # end | |
15 | + # | |
16 | + # Your routes should be something like: | |
17 | + # | |
18 | + # m.resources :files, :has_many => :comments #=> /files/13/comments | |
19 | + # m.resources :tasks, :has_many => :comments #=> /tasks/17/comments | |
20 | + # m.resources :messages, :has_many => :comments #=> /messages/11/comments | |
21 | + # | |
22 | + # When using polymorphic associations, you get some free helpers: | |
23 | + # | |
24 | + # parent? #=> true | |
25 | + # parent_type #=> :task | |
26 | + # parent_class #=> Task | |
27 | + # parent #=> @task | |
28 | + # | |
29 | + # This polymorphic controllers thing is a great idea by James Golick and he | |
30 | + # built it in resource_controller. Here is just a re-implementation. | |
31 | + # | |
32 | + # = optional polymorphic associations | |
33 | + # | |
34 | + # Let's take another break from ProjectsController. Let's suppose we are | |
35 | + # building a store, which sell products. | |
36 | + # | |
37 | + # On the website, we can show all products, but also products scoped to | |
38 | + # categories, brands, users. In this case case, the association is optional, and | |
39 | + # we deal with it in the following way: | |
40 | + # | |
41 | + # class ProductsController < InheritedResources::Base | |
42 | + # belongs_to :category, :brand, :user, :polymorphic => true, :optional => true | |
43 | + # end | |
44 | + # | |
45 | + # This will handle all those urls properly: | |
46 | + # | |
47 | + # /products/1 | |
48 | + # /categories/2/products/5 | |
49 | + # /brands/10/products/3 | |
50 | + # /user/13/products/11 | |
51 | + # | |
52 | + # = nested polymorphic associations | |
53 | + # | |
54 | + # You can have polymorphic associations with nested resources. Let's suppose | |
55 | + # that our File, Task and Message resources in the previous example belongs to | |
56 | + # a project. | |
57 | + # | |
58 | + # This way we can have: | |
59 | + # | |
60 | + # class CommentsController < InheritedResources::Base | |
61 | + # belongs_to :project { | |
62 | + # belongs_to :file, :message, :task, :polymorphic => true | |
63 | + # } | |
64 | + # end | |
65 | + # | |
66 | + # Or: | |
67 | + # | |
68 | + # class CommentsController < InheritedResources::Base | |
69 | + # nested_belongs_to :project | |
70 | + # nested_belongs_to :file, :message, :task, :polymorphic => true | |
71 | + # end | |
72 | + # | |
73 | + # Choose the syntax that makes more sense to you. :) | |
74 | + # | |
75 | + # Finally your routes should be something like: | |
76 | + # | |
77 | + # map.resources :projects do |m| | |
78 | + # m.resources :files, :has_many => :comments #=> /projects/1/files/13/comments | |
79 | + # m.resources :tasks, :has_many => :comments #=> /projects/1/tasks/17/comments | |
80 | + # m.resources :messages, :has_many => :comments #=> /projects/1/messages/11/comments | |
81 | + # end | |
82 | + # | |
83 | + # The helpers work in the same way as above. | |
84 | + # | |
85 | + module PolymorphicHelpers | |
86 | + | |
87 | + protected | |
88 | + | |
89 | + # Returns the parent type. A Comments class can have :task, :file, :note | |
90 | + # as parent types. | |
91 | + # | |
92 | + def parent_type | |
93 | + @parent_type | |
94 | + end | |
95 | + | |
96 | + def parent_class | |
97 | + parent.class if @parent_type | |
98 | + end | |
99 | + | |
100 | + # Returns the parent object. They are also available with the instance | |
101 | + # variable name: @task, @file, @note... | |
102 | + # | |
103 | + def parent | |
104 | + instance_variable_get("@#{@parent_type}") if @parent_type | |
105 | + end | |
106 | + | |
107 | + # If the polymorphic association is optional, we might not have a parent. | |
108 | + # | |
109 | + def parent? | |
110 | + if resources_configuration[:polymorphic][:optional] | |
111 | + parents_symbols.size > 1 || !@parent_type.nil? | |
112 | + else | |
113 | + true | |
114 | + end | |
115 | + end | |
116 | + | |
117 | + private | |
118 | + | |
119 | + # Maps parents_symbols to build association chain. | |
120 | + # | |
121 | + # If the parents_symbols find :polymorphic, it goes through the | |
122 | + # params keys to see which polymorphic parent matches the given params. | |
123 | + # | |
124 | + # When optional is given, it does not raise errors if the polymorphic | |
125 | + # params are missing. | |
126 | + # | |
127 | + def symbols_for_association_chain #:nodoc: | |
128 | + polymorphic_config = resources_configuration[:polymorphic] | |
129 | + | |
130 | + parents_symbols.map do |symbol| | |
131 | + if symbol == :polymorphic | |
132 | + params_keys = params.keys | |
133 | + | |
134 | + key = polymorphic_config[:symbols].find do |poly| | |
135 | + params_keys.include? resources_configuration[poly][:param].to_s | |
136 | + end | |
137 | + | |
138 | + if key.nil? | |
139 | + raise ScriptError, "Could not find param for polymorphic association. | |
140 | + The request params keys are #{params.keys.inspect} | |
141 | + and the polymorphic associations are | |
142 | + #{polymorphic_symbols.inspect}." unless polymorphic_config[:optional] | |
143 | + | |
144 | + nil | |
145 | + else | |
146 | + @parent_type = key.to_sym | |
147 | + end | |
148 | + else | |
149 | + symbol | |
150 | + end | |
151 | + end.compact | |
152 | + end | |
153 | + | |
154 | + end | |
155 | +end | |
156 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/respond_to.rb
0 → 100644
... | ... | @@ -0,0 +1,339 @@ |
1 | +module ActionController | |
2 | + # Provides an extension for Rails respond_to by expading MimeResponds::Responder | |
3 | + # and adding respond_to class method and respond_with instance method. | |
4 | + # | |
5 | + class Base | |
6 | + | |
7 | + protected | |
8 | + # Defines respond_to method to store formats that are rendered by default. | |
9 | + # | |
10 | + # Examples: | |
11 | + # | |
12 | + # respond_to :html, :xml, :json | |
13 | + # | |
14 | + # All actions on your controller will respond to :html, :xml and :json. | |
15 | + # But if you want to specify it based on your actions, you can use only and | |
16 | + # except: | |
17 | + # | |
18 | + # respond_to :html | |
19 | + # respond_to :xml, :json, :except => [ :edit ] | |
20 | + # | |
21 | + # The definition above explicits that all actions respond to :html. And all | |
22 | + # actions except :edit respond to :xml and :json. | |
23 | + # | |
24 | + # You can specify also only parameters: | |
25 | + # | |
26 | + # respond_to :rjs, :only => :create | |
27 | + # | |
28 | + # Which would be the same as: | |
29 | + # | |
30 | + # respond_to :rjs => :create | |
31 | + # | |
32 | + def self.respond_to(*formats) | |
33 | + options = formats.extract_options! | |
34 | + formats_hash = {} | |
35 | + | |
36 | + only_actions = Array(options.delete(:only)) | |
37 | + except_actions = Array(options.delete(:except)) | |
38 | + | |
39 | + only_actions.map!{ |a| a.to_sym } | |
40 | + except_actions.map!{ |a| a.to_sym } | |
41 | + | |
42 | + formats.each do |format| | |
43 | + formats_hash[format.to_sym] = {} | |
44 | + formats_hash[format.to_sym][:only] = only_actions unless only_actions.empty? | |
45 | + formats_hash[format.to_sym][:except] = except_actions unless except_actions.empty? | |
46 | + end | |
47 | + | |
48 | + options.each do |format, actions| | |
49 | + formats_hash[format.to_sym] = {} | |
50 | + next if actions == :all || actions == 'all' | |
51 | + | |
52 | + actions = Array(actions) | |
53 | + actions.map!{ |a| a.to_sym } | |
54 | + | |
55 | + formats_hash[format.to_sym][:only] = actions unless actions.empty? | |
56 | + end | |
57 | + | |
58 | + write_inheritable_hash(:formats_for_respond_to, formats_hash) | |
59 | + end | |
60 | + class_inheritable_reader :formats_for_respond_to | |
61 | + | |
62 | + # Method to clear all respond_to declared until the current controller. | |
63 | + # This is like freeing the controller from the inheritance chain. :) | |
64 | + # | |
65 | + def self.clear_respond_to! | |
66 | + formats = formats_for_respond_to | |
67 | + formats.each { |k,v| formats[k] = { :only => [] } } | |
68 | + write_inheritable_hash(:formats_for_respond_to, formats) | |
69 | + end | |
70 | + | |
71 | + # By default, responds only to :html | |
72 | + respond_to :html | |
73 | + | |
74 | + # If ApplicationController is already defined around here, we recriate | |
75 | + # the formats_for_respond_to hash. Since we respond only to :html by | |
76 | + # default, this is as easy as settings the :formats_for_respond_to key | |
77 | + # to {:html=>{}}. | |
78 | + # | |
79 | + if defined?(ApplicationController) | |
80 | + if inheritable = ApplicationController.instance_variable_get("@inheritable_attributes") | |
81 | + inheritable.merge!(:formats_for_respond_to => {:html => {}}) if inheritable | |
82 | + end | |
83 | + end | |
84 | + | |
85 | + # respond_with accepts an object and tries to render a view based in the | |
86 | + # controller and actions that called respond_with. If the view cannot be | |
87 | + # found, it will try to call :to_format in the object. | |
88 | + # | |
89 | + # class ProjectsController < ApplicationController | |
90 | + # respond_to :html, :xml | |
91 | + # | |
92 | + # def show | |
93 | + # @project = Project.find(:id) | |
94 | + # respond_with(@project) | |
95 | + # end | |
96 | + # end | |
97 | + # | |
98 | + # When the client request a xml, we will check first for projects/show.xml | |
99 | + # if it can't be found, we will call :to_xml in the object @project. If the | |
100 | + # object eventually doesn't respond to :to_xml it will render 404. | |
101 | + # | |
102 | + # If you want to overwrite the formats specified in the class, you can | |
103 | + # send your new formats using the options :to. | |
104 | + # | |
105 | + # def show | |
106 | + # @project = Project.find(:id) | |
107 | + # respond_with(@project, :to => :json) | |
108 | + # end | |
109 | + # | |
110 | + # That means that this action will ONLY reply to json requests. | |
111 | + # | |
112 | + # All other options sent will be forwarded to the render method. So you can | |
113 | + # do: | |
114 | + # | |
115 | + # def create | |
116 | + # # ... | |
117 | + # if @project.save | |
118 | + # respond_with(@project, :status => :ok, :location => @project) | |
119 | + # else | |
120 | + # respond_with(@project.errors, :status => :unprocessable_entity) | |
121 | + # end | |
122 | + # end | |
123 | + # | |
124 | + # respond_with does not accept blocks, if you want advanced configurations | |
125 | + # check respond_to method sending :with => @object as option. | |
126 | + # | |
127 | + # Returns true if anything is rendered. Returns false otherwise. | |
128 | + # | |
129 | + def respond_with(object, options = {}) | |
130 | + attempt_to_respond = false | |
131 | + | |
132 | + responder = options.delete(:responder) || Responder.new(self) | |
133 | + skip_not_acceptable = options.delete(:skip_not_acceptable) | |
134 | + skip_default_template = options.delete(:skip_default_template) | |
135 | + | |
136 | + mime_types = Array(options.delete(:to)) | |
137 | + mime_types.map!{ |mime| mime.to_sym } | |
138 | + | |
139 | + for priority in responder.mime_type_priority | |
140 | + if !skip_default_template && priority == Mime::ALL && respond_to_default_template?(responder) | |
141 | + render options.merge(:action => action_name) | |
142 | + return true | |
143 | + | |
144 | + elsif responder.action_respond_to_format?(priority.to_sym, mime_types) | |
145 | + attempt_to_respond = true | |
146 | + response.template.template_format = priority.to_sym | |
147 | + response.content_type = priority.to_s | |
148 | + | |
149 | + if template_exists? | |
150 | + render options.merge(:action => action_name) | |
151 | + return true | |
152 | + elsif object.respond_to?(:"to_#{priority.to_sym}") | |
153 | + render options.merge(:text => object.send(:"to_#{priority.to_sym}")) | |
154 | + return true | |
155 | + end | |
156 | + end | |
157 | + end | |
158 | + | |
159 | + # If we got here we could not render the object. But if attempted to | |
160 | + # render (this means, the format sent by the client was valid) we should | |
161 | + # render a 404. | |
162 | + # | |
163 | + # If we even didn't attempt to respond, we respond :not_acceptable | |
164 | + # unless is told otherwise. | |
165 | + # | |
166 | + if attempt_to_respond | |
167 | + render :text => '404 Not Found', :status => 404 | |
168 | + return true | |
169 | + elsif !skip_not_acceptable | |
170 | + head :not_acceptable | |
171 | + return false | |
172 | + end | |
173 | + | |
174 | + return false | |
175 | + end | |
176 | + | |
177 | + # Extends respond_to behaviour. | |
178 | + # | |
179 | + # You can now pass objects using the options :with. | |
180 | + # | |
181 | + # respond_to(:html, :xml, :rjs, :with => @project) | |
182 | + # | |
183 | + # If you pass an object and send any block, it's exactly the same as: | |
184 | + # | |
185 | + # respond_with(@project, :to => [:html, :xml, :rjs]) | |
186 | + # | |
187 | + # But the main difference of respond_to and respond_with is that the first | |
188 | + # allows further customizations: | |
189 | + # | |
190 | + # respond_to(:html, :with => @project) do |format| | |
191 | + # format.xml { render :xml => @project.errors } | |
192 | + # end | |
193 | + # | |
194 | + # It's the same as: | |
195 | + # | |
196 | + # 1. When responding to html, execute respond_with(@object). | |
197 | + # 2. When accessing a xml, execute the block given. | |
198 | + # | |
199 | + # Formats defined in blocks have precedence to formats sent as arguments. | |
200 | + # In other words, if you pass a format as argument and as block, the block | |
201 | + # will always be executed. | |
202 | + # | |
203 | + # And as in respond_with, all extra options sent will be forwarded to | |
204 | + # the render method: | |
205 | + # | |
206 | + # respond_to(:with => @projects.errors, :status => :unprocessable_entity) do |format| | |
207 | + # format.html { render :template => 'new' } | |
208 | + # end | |
209 | + # | |
210 | + # It also accepts an option called prioritize. It allows you to put a | |
211 | + # format as first, and then when Mime::ALL is sent, it will be the one | |
212 | + # used as response. | |
213 | + # | |
214 | + def respond_to(*types, &block) | |
215 | + options = types.extract_options! | |
216 | + | |
217 | + object = options.delete(:with) | |
218 | + responder = options.delete(:responder) || Responder.new(self) | |
219 | + prioritize = options.delete(:prioritize) | |
220 | + | |
221 | + if object.nil? | |
222 | + block ||= lambda { |responder| types.each { |type| responder.send(type) } } | |
223 | + block.call(responder) | |
224 | + responder.respond | |
225 | + return true | |
226 | + else | |
227 | + # Even if Mime::ALL is sent by the client, we do not respond_to it now. | |
228 | + # This is done using calling :respond_except_any instead of :respond. | |
229 | + # | |
230 | + if block_given? | |
231 | + block.call(responder) | |
232 | + return true if responder.respond_except_any | |
233 | + end | |
234 | + | |
235 | + # If the block includes the default template format, we don't render | |
236 | + # the default template (which uses the default_template_format). | |
237 | + options.merge!(:to => types, :responder => responder, :skip_not_acceptable => true, | |
238 | + :skip_default_template => responder.order.include?(default_template_format)) | |
239 | + | |
240 | + if respond_with(object, options) | |
241 | + return true | |
242 | + elsif block_given? | |
243 | + responder.prioritize(prioritize) if prioritize | |
244 | + return true if responder.respond_any | |
245 | + end | |
246 | + end | |
247 | + | |
248 | + head :not_acceptable | |
249 | + return false | |
250 | + end | |
251 | + | |
252 | + private | |
253 | + | |
254 | + unless ActionController::Base.private_instance_methods.include?('template_exists?') || | |
255 | + ActionController::Base.private_instance_methods.include?(:template_exists?) | |
256 | + | |
257 | + # Define template_exists? for Rails 2.3 | |
258 | + def template_exists? | |
259 | + default_template ? true : false | |
260 | + rescue ActionView::MissingTemplate | |
261 | + false | |
262 | + end | |
263 | + end | |
264 | + | |
265 | + # We respond to the default template if it's a valid format AND the template | |
266 | + # exists. | |
267 | + # | |
268 | + def respond_to_default_template?(responder) #:nodoc: | |
269 | + responder.action_respond_to_format?(default_template_format) && template_exists? | |
270 | + end | |
271 | + | |
272 | + end | |
273 | + | |
274 | + module MimeResponds #:nodoc: | |
275 | + class Responder #:nodoc: | |
276 | + | |
277 | + attr_reader :mime_type_priority, :order | |
278 | + | |
279 | + # Similar as respond but if we can't find a valid mime type, we do not | |
280 | + # send :not_acceptable message as head and it does not respond to | |
281 | + # Mime::ALL in any case. | |
282 | + # | |
283 | + def respond_except_any | |
284 | + for priority in @mime_type_priority | |
285 | + next if priority == Mime::ALL | |
286 | + | |
287 | + if @responses[priority] | |
288 | + @responses[priority].call | |
289 | + return true | |
290 | + end | |
291 | + end | |
292 | + | |
293 | + false | |
294 | + end | |
295 | + | |
296 | + # Respond to the first format given if Mime::ALL is included in the | |
297 | + # mime type priorites. This is the behaviour expected when the client | |
298 | + # sends "*/*" as mime type. | |
299 | + # | |
300 | + def respond_any | |
301 | + any = @responses[@order.include?(Mime::ALL) ? Mime::ALL : @order.first] | |
302 | + | |
303 | + if any && @mime_type_priority.include?(Mime::ALL) | |
304 | + any.call | |
305 | + return true | |
306 | + end | |
307 | + end | |
308 | + | |
309 | + # Receives an format and checks if the current action responds to | |
310 | + # the given format. If additional mimes are sent, only them are checked. | |
311 | + # | |
312 | + def action_respond_to_format?(format, additional_mimes = []) | |
313 | + if !additional_mimes.blank? | |
314 | + additional_mimes.include?(format.to_sym) | |
315 | + elsif formats = @controller.formats_for_respond_to[format.to_sym] | |
316 | + if formats[:only] | |
317 | + formats[:only].include?(@controller.action_name.to_sym) | |
318 | + elsif formats[:except] | |
319 | + !formats[:except].include?(@controller.action_name.to_sym) | |
320 | + else | |
321 | + true | |
322 | + end | |
323 | + else | |
324 | + false | |
325 | + end | |
326 | + end | |
327 | + | |
328 | + # Makes a given format the first in the @order array. | |
329 | + # | |
330 | + def prioritize(format) | |
331 | + if index = @order.index(format) | |
332 | + @order.unshift(@order.delete_at(index)) | |
333 | + end | |
334 | + @order | |
335 | + end | |
336 | + | |
337 | + end | |
338 | + end | |
339 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/singleton_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,95 @@ |
1 | +module InheritedResources | |
2 | + | |
3 | + # = singleton | |
4 | + # | |
5 | + # Singletons are usually used in associations which are related through has_one | |
6 | + # and belongs_to. You declare those associations like this: | |
7 | + # | |
8 | + # class ManagersController < InheritedResources::Base | |
9 | + # belongs_to :project, :singleton => true | |
10 | + # end | |
11 | + # | |
12 | + # But in some cases, like an AccountsController, you have a singleton object | |
13 | + # that is not necessarily associated with another: | |
14 | + # | |
15 | + # class AccountsController < InheritedResources::Base | |
16 | + # defaults :singleton => true | |
17 | + # end | |
18 | + # | |
19 | + # Besides that, you should overwrite the methods :resource and :build_resource | |
20 | + # to make it work properly: | |
21 | + # | |
22 | + # class AccountsController < InheritedResources::Base | |
23 | + # defaults :singleton => true | |
24 | + # | |
25 | + # protected | |
26 | + # def resource | |
27 | + # @current_user.account | |
28 | + # end | |
29 | + # | |
30 | + # def build_resource(attributes = {}) | |
31 | + # Account.new(attributes) | |
32 | + # end | |
33 | + # end | |
34 | + # | |
35 | + # When you have a singleton controller, the action index is removed. | |
36 | + # | |
37 | + module SingletonHelpers | |
38 | + | |
39 | + protected | |
40 | + | |
41 | + # Singleton methods does not deal with collections. | |
42 | + # | |
43 | + def collection | |
44 | + nil | |
45 | + end | |
46 | + | |
47 | + # Overwrites how singleton deals with resource. | |
48 | + # | |
49 | + # If you are going to overwrite it, you should notice that the | |
50 | + # end_of_association_chain here is not the same as in default belongs_to. | |
51 | + # | |
52 | + # class TasksController < InheritedResources::Base | |
53 | + # belongs_to :project | |
54 | + # end | |
55 | + # | |
56 | + # In this case, the association chain would be: | |
57 | + # | |
58 | + # Project.find(params[:project_id]).tasks | |
59 | + # | |
60 | + # So you would just have to call find(:all) at the end of association | |
61 | + # chain. And this is what happened. | |
62 | + # | |
63 | + # In singleton controllers: | |
64 | + # | |
65 | + # class ManagersController < InheritedResources::Base | |
66 | + # belongs_to :project, :singleton => true | |
67 | + # end | |
68 | + # | |
69 | + # The association chain will be: | |
70 | + # | |
71 | + # Project.find(params[:project_id]) | |
72 | + # | |
73 | + # So we have to call manager on it, not find. | |
74 | + # | |
75 | + def resource | |
76 | + get_resource_ivar || set_resource_ivar(end_of_association_chain.send(resource_instance_name)) | |
77 | + end | |
78 | + | |
79 | + private | |
80 | + | |
81 | + # Returns the appropriated method to build the resource. | |
82 | + # | |
83 | + def method_for_association_build #:nodoc: | |
84 | + :"build_#{resource_instance_name}" | |
85 | + end | |
86 | + | |
87 | + # Sets the method_for_association_chain to nil. See <tt>resource</tt> | |
88 | + # above for more information. | |
89 | + # | |
90 | + def method_for_association_chain #:nodoc: | |
91 | + nil | |
92 | + end | |
93 | + | |
94 | + end | |
95 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/lib/inherited_resources/url_helpers.rb
0 → 100644
... | ... | @@ -0,0 +1,173 @@ |
1 | +module InheritedResources | |
2 | + # = URLHelpers | |
3 | + # | |
4 | + # When you use InheritedResources it creates some UrlHelpers for you. | |
5 | + # And they handle everything for you. | |
6 | + # | |
7 | + # # /posts/1/comments | |
8 | + # resource_url # => /posts/1/comments/#{@comment.to_param} | |
9 | + # resource_url(comment) # => /posts/1/comments/#{comment.to_param} | |
10 | + # new_resource_url # => /posts/1/comments/new | |
11 | + # edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit | |
12 | + # collection_url # => /posts/1/comments | |
13 | + # | |
14 | + # # /projects/1/tasks | |
15 | + # resource_url # => /products/1/tasks/#{@task.to_param} | |
16 | + # resource_url(task) # => /products/1/tasks/#{task.to_param} | |
17 | + # new_resource_url # => /products/1/tasks/new | |
18 | + # edit_resource_url # => /products/1/tasks/#{@task.to_param}/edit | |
19 | + # collection_url # => /products/1/tasks | |
20 | + # | |
21 | + # # /users | |
22 | + # resource_url # => /users/#{@user.to_param} | |
23 | + # resource_url(user) # => /users/#{user.to_param} | |
24 | + # new_resource_url # => /users/new | |
25 | + # edit_resource_url # => /users/#{@user.to_param}/edit | |
26 | + # collection_url # => /users | |
27 | + # | |
28 | + # The nice thing is that those urls are not guessed during runtime. They are | |
29 | + # all created when you inherit. | |
30 | + # | |
31 | + module UrlHelpers | |
32 | + | |
33 | + # This method hard code url helpers in the class. | |
34 | + # | |
35 | + # We are doing this because is cheaper than guessing them when our action | |
36 | + # is being processed (and even more cheaper when we are using nested | |
37 | + # resources). | |
38 | + # | |
39 | + # When we are using polymorphic associations, those helpers rely on | |
40 | + # polymorphic_url Rails helper. | |
41 | + # | |
42 | + def create_resources_url_helpers! | |
43 | + resource_segments, resource_ivars = [], [] | |
44 | + resource_config = self.resources_configuration[:self] | |
45 | + | |
46 | + singleton = self.resources_configuration[:self][:singleton] | |
47 | + polymorphic = self.parents_symbols.include?(:polymorphic) | |
48 | + | |
49 | + # Add route_prefix if any. | |
50 | + unless resource_config[:route_prefix].blank? | |
51 | + if polymorphic | |
52 | + resource_ivars << resource_config[:route_prefix].to_s.inspect | |
53 | + else | |
54 | + resource_segments << resource_config[:route_prefix] | |
55 | + end | |
56 | + end | |
57 | + | |
58 | + # Deal with belongs_to associations and polymorphic associations. | |
59 | + # Remember that we don't have to build the segments in polymorphic cases, | |
60 | + # because the url will be polymorphic_url. | |
61 | + # | |
62 | + self.parents_symbols.each do |symbol| | |
63 | + if symbol == :polymorphic | |
64 | + resource_ivars << :parent | |
65 | + else | |
66 | + config = self.resources_configuration[symbol] | |
67 | + resource_segments << config[:route_name] | |
68 | + resource_ivars << :"@#{config[:instance_name]}" | |
69 | + end | |
70 | + end | |
71 | + | |
72 | + collection_ivars = resource_ivars.dup | |
73 | + collection_segments = resource_segments.dup | |
74 | + | |
75 | + # This is the default route configuration, later we have to deal with | |
76 | + # exception from polymorphic and singleton cases. | |
77 | + # | |
78 | + collection_segments << resource_config[:route_collection_name] | |
79 | + resource_segments << resource_config[:route_instance_name] | |
80 | + resource_ivars << :"@#{resource_config[:instance_name]}" | |
81 | + | |
82 | + # In singleton cases, we do not send the current element instance variable | |
83 | + # because the id is not in the URL. For example, we should call: | |
84 | + # | |
85 | + # project_manager_url(@project) | |
86 | + # | |
87 | + # Instead of: | |
88 | + # | |
89 | + # project_manager_url(@project, @manager) | |
90 | + # | |
91 | + # Another exception in singleton cases is that collection url does not | |
92 | + # exist. In such cases, we create the parent collection url. So in the | |
93 | + # manager case above, the collection url will be: | |
94 | + # | |
95 | + # project_url(@project) | |
96 | + # | |
97 | + # If the singleton does not have a parent, it will default to root_url. | |
98 | + # | |
99 | + # Finally, polymorphic cases we have to give hints to the polymorphic url | |
100 | + # builder. This works by attaching new ivars as symbols or records. | |
101 | + # | |
102 | + if singleton | |
103 | + collection_segments.pop | |
104 | + resource_ivars.pop | |
105 | + | |
106 | + if polymorphic | |
107 | + resource_ivars << resource_config[:instance_name].inspect | |
108 | + new_ivars = resource_ivars | |
109 | + end | |
110 | + elsif polymorphic | |
111 | + collection_ivars << '(@_resource_class_new ||= resource_class.new)' | |
112 | + end | |
113 | + | |
114 | + generate_url_and_path_helpers nil, :collection, collection_segments, collection_ivars | |
115 | + generate_url_and_path_helpers :new, :resource, resource_segments, new_ivars || collection_ivars | |
116 | + generate_url_and_path_helpers nil, :resource, resource_segments, resource_ivars | |
117 | + generate_url_and_path_helpers :edit, :resource, resource_segments, resource_ivars | |
118 | + end | |
119 | + | |
120 | + def generate_url_and_path_helpers(prefix, name, resource_segments, resource_ivars) #:nodoc: | |
121 | + ivars = resource_ivars.dup | |
122 | + | |
123 | + singleton = self.resources_configuration[:self][:singleton] | |
124 | + polymorphic = self.parents_symbols.include?(:polymorphic) | |
125 | + | |
126 | + # If it's not a singleton, ivars are not empty, not a collection or | |
127 | + # not a "new" named route, we can pass a resource as argument. | |
128 | + # | |
129 | + unless singleton || ivars.empty? || name == :collection || prefix == :new | |
130 | + ivars.push "(given_args.first || #{ivars.pop})" | |
131 | + end | |
132 | + | |
133 | + # In collection in polymorphic cases, allow an argument to be given as a | |
134 | + # replacemente for the parent. | |
135 | + # | |
136 | + if name == :collection && polymorphic | |
137 | + index = ivars.index(:parent) | |
138 | + ivars.insert index, "(given_args.first || parent)" | |
139 | + ivars.delete(:parent) | |
140 | + end | |
141 | + | |
142 | + # When polymorphic is true, the segments must be replace by :polymorphic | |
143 | + # and ivars should be gathered into an array, which is compacted when | |
144 | + # optional. | |
145 | + # | |
146 | + if polymorphic | |
147 | + segments = :polymorphic | |
148 | + ivars = "[#{ivars.join(', ')}]" | |
149 | + ivars << '.compact' if self.resources_configuration[:polymorphic][:optional] | |
150 | + else | |
151 | + segments = resource_segments.empty? ? 'root' : resource_segments.join('_') | |
152 | + ivars = ivars.join(', ') | |
153 | + end | |
154 | + | |
155 | + prefix = prefix ? "#{prefix}_" : '' | |
156 | + ivars << (ivars.empty? ? 'given_options' : ', given_options') | |
157 | + | |
158 | + class_eval <<-URL_HELPERS, __FILE__, __LINE__ | |
159 | + protected | |
160 | + def #{prefix}#{name}_path(*given_args) | |
161 | + given_options = given_args.extract_options! | |
162 | + #{prefix}#{segments}_path(#{ivars}) | |
163 | + end | |
164 | + | |
165 | + def #{prefix}#{name}_url(*given_args) | |
166 | + given_options = given_args.extract_options! | |
167 | + #{prefix}#{segments}_url(#{ivars}) | |
168 | + end | |
169 | + URL_HELPERS | |
170 | + end | |
171 | + | |
172 | + end | |
173 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/aliases_test.rb
0 → 100644
... | ... | @@ -0,0 +1,134 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Student; | |
4 | + def self.human_name; 'Student'; end | |
5 | +end | |
6 | + | |
7 | +class StudentsController < ApplicationController | |
8 | + inherit_resources | |
9 | + | |
10 | + def edit | |
11 | + edit! do |format| | |
12 | + format.xml { render :text => 'Render XML' } | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + def new | |
17 | + @something = 'magical' | |
18 | + new! | |
19 | + end | |
20 | + | |
21 | + def create | |
22 | + create! do |success, failure| | |
23 | + success.html { render :text => "I won't redirect!" } | |
24 | + failure.xml { render :text => "I shouldn't be rendered" } | |
25 | + end | |
26 | + end | |
27 | + | |
28 | + def update | |
29 | + update! do |success, failure| | |
30 | + success.html { redirect_to(resource_url) } | |
31 | + failure.html { render :text => "I won't render!" } | |
32 | + end | |
33 | + end | |
34 | + | |
35 | + def destroy | |
36 | + destroy! do |format| | |
37 | + format.html { render :text => "Destroyed!" } | |
38 | + end | |
39 | + end | |
40 | + | |
41 | +end | |
42 | + | |
43 | +class AliasesTest < ActionController::TestCase | |
44 | + tests StudentsController | |
45 | + | |
46 | + def test_assignments_before_calling_alias | |
47 | + Student.stubs(:new).returns(mock_student) | |
48 | + get :new | |
49 | + assert_response :success | |
50 | + assert_equal 'magical', assigns(:something) | |
51 | + end | |
52 | + | |
53 | + def test_controller_should_render_new | |
54 | + Student.stubs(:new).returns(mock_student) | |
55 | + get :new | |
56 | + assert_response :success | |
57 | + assert_equal 'New HTML', @response.body.strip | |
58 | + end | |
59 | + | |
60 | + def test_expose_the_resquested_user_on_edit | |
61 | + Student.expects(:find).with('42').returns(mock_student) | |
62 | + get :edit, :id => '42' | |
63 | + assert_equal mock_student, assigns(:student) | |
64 | + assert_response :success | |
65 | + end | |
66 | + | |
67 | + def test_controller_should_render_edit | |
68 | + Student.stubs(:find).returns(mock_student) | |
69 | + get :edit | |
70 | + assert_response :success | |
71 | + assert_equal 'Edit HTML', @response.body.strip | |
72 | + end | |
73 | + | |
74 | + def test_render_xml_when_it_is_given_as_a_block | |
75 | + @request.accept = 'application/xml' | |
76 | + Student.stubs(:find).returns(mock_student) | |
77 | + get :edit | |
78 | + assert_response :success | |
79 | + assert_equal 'Render XML', @response.body | |
80 | + end | |
81 | + | |
82 | + def test_is_not_redirected_on_create_with_success_if_success_block_is_given | |
83 | + Student.stubs(:new).returns(mock_student(:save => true)) | |
84 | + @controller.stubs(:resource_url).returns('http://test.host/') | |
85 | + post :create | |
86 | + assert_response :success | |
87 | + assert_equal "I won't redirect!", @response.body | |
88 | + end | |
89 | + | |
90 | + def test_dumb_responder_quietly_receives_everything_on_failure | |
91 | + @request.accept = 'text/html' | |
92 | + Student.stubs(:new).returns(mock_student(:save => false, :errors => [])) | |
93 | + @controller.stubs(:resource_url).returns('http://test.host/') | |
94 | + post :create | |
95 | + assert_response :success | |
96 | + assert_equal "New HTML", @response.body.strip | |
97 | + end | |
98 | + | |
99 | + def test_html_is_the_default_when_only_xml_is_overwriten | |
100 | + @request.accept = '*/*' | |
101 | + Student.stubs(:new).returns(mock_student(:save => false, :errors => [])) | |
102 | + @controller.stubs(:resource_url).returns('http://test.host/') | |
103 | + post :create | |
104 | + assert_response :success | |
105 | + assert_equal "New HTML", @response.body.strip | |
106 | + end | |
107 | + | |
108 | + def test_wont_render_edit_template_on_update_with_failure_if_failure_block_is_given | |
109 | + Student.stubs(:find).returns(mock_student(:update_attributes => false, :errors => [])) | |
110 | + put :update | |
111 | + assert_response :success | |
112 | + assert_equal "I won't render!", @response.body | |
113 | + end | |
114 | + | |
115 | + def test_dumb_responder_quietly_receives_everything_on_success | |
116 | + Student.stubs(:find).returns(mock_student(:update_attributes => true)) | |
117 | + @controller.stubs(:resource_url).returns('http://test.host/') | |
118 | + put :update, :id => '42', :student => {:these => 'params'} | |
119 | + assert_equal mock_student, assigns(:student) | |
120 | + end | |
121 | + | |
122 | + def test_block_is_called_when_student_is_destroyed | |
123 | + Student.stubs(:find).returns(mock_student(:destroy => true)) | |
124 | + delete :destroy | |
125 | + assert_response :success | |
126 | + assert_equal "Destroyed!", @response.body | |
127 | + end | |
128 | + | |
129 | + protected | |
130 | + def mock_student(stubs={}) | |
131 | + @mock_student ||= mock(stubs) | |
132 | + end | |
133 | +end | |
134 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/base_helpers_test.rb
0 → 100644
... | ... | @@ -0,0 +1,70 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Pet | |
4 | + def self.human_name; 'Pet'; end | |
5 | +end | |
6 | + | |
7 | +class PetsController < InheritedResources::Base | |
8 | + attr_accessor :current_user | |
9 | + | |
10 | + def edit | |
11 | + @pet = 'new pet' | |
12 | + edit! | |
13 | + end | |
14 | + | |
15 | + protected | |
16 | + def collection | |
17 | + @pets ||= end_of_association_chain.all | |
18 | + end | |
19 | + | |
20 | + def begin_of_association_chain | |
21 | + @current_user | |
22 | + end | |
23 | +end | |
24 | + | |
25 | +class AssociationChainBaseHelpersTest < ActionController::TestCase | |
26 | + tests PetsController | |
27 | + | |
28 | + def setup | |
29 | + @controller.current_user = mock() | |
30 | + end | |
31 | + | |
32 | + def test_begin_of_association_chain_is_called_on_index | |
33 | + @controller.current_user.expects(:pets).returns(Pet) | |
34 | + Pet.expects(:all).returns(mock_pet) | |
35 | + get :index | |
36 | + assert_response :success | |
37 | + assert 'Index HTML', @response.body.strip | |
38 | + end | |
39 | + | |
40 | + def test_begin_of_association_chain_is_called_on_new | |
41 | + @controller.current_user.expects(:pets).returns(Pet) | |
42 | + Pet.expects(:build).returns(mock_pet) | |
43 | + get :new | |
44 | + assert_response :success | |
45 | + assert 'New HTML', @response.body.strip | |
46 | + end | |
47 | + | |
48 | + def test_begin_of_association_chain_is_called_on_show | |
49 | + @controller.current_user.expects(:pets).returns(Pet) | |
50 | + Pet.expects(:find).with('47').returns(mock_pet) | |
51 | + get :show, :id => '47' | |
52 | + assert_response :success | |
53 | + assert 'Show HTML', @response.body.strip | |
54 | + end | |
55 | + | |
56 | + def test_instance_variable_should_not_be_set_if_already_defined | |
57 | + @controller.current_user.expects(:pets).never | |
58 | + Pet.expects(:find).never | |
59 | + get :edit | |
60 | + assert_response :success | |
61 | + assert_equal 'new pet', assigns(:pet) | |
62 | + end | |
63 | + | |
64 | + protected | |
65 | + def mock_pet(stubs={}) | |
66 | + @mock_pet ||= mock(stubs) | |
67 | + end | |
68 | + | |
69 | +end | |
70 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/base_test.rb
0 → 100644
... | ... | @@ -0,0 +1,219 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class User | |
4 | + def self.human_name; 'User'; end | |
5 | +end | |
6 | + | |
7 | +class AccountsController < InheritedResources::Base | |
8 | +end | |
9 | + | |
10 | +class UsersController < AccountsController | |
11 | + respond_to :html, :xml | |
12 | +end | |
13 | + | |
14 | +module UserTestHelper | |
15 | + def setup | |
16 | + @controller = UsersController.new | |
17 | + @controller.request = @request = ActionController::TestRequest.new | |
18 | + @controller.response = @response = ActionController::TestResponse.new | |
19 | + end | |
20 | + | |
21 | + protected | |
22 | + def mock_user(stubs={}) | |
23 | + @mock_user ||= mock(stubs) | |
24 | + end | |
25 | +end | |
26 | + | |
27 | +class IndexActionBaseTest < ActionController::TestCase | |
28 | + include UserTestHelper | |
29 | + | |
30 | + def test_expose_all_users_as_instance_variable | |
31 | + User.expects(:find).with(:all).returns([mock_user]) | |
32 | + get :index | |
33 | + assert_equal [mock_user], assigns(:users) | |
34 | + end | |
35 | + | |
36 | + def test_controller_should_render_index | |
37 | + User.stubs(:find).returns([mock_user]) | |
38 | + get :index | |
39 | + assert_response :success | |
40 | + assert_equal 'Index HTML', @response.body.strip | |
41 | + end | |
42 | + | |
43 | + def test_render_all_users_as_xml_when_mime_type_is_xml | |
44 | + @request.accept = 'application/xml' | |
45 | + User.expects(:find).with(:all).returns(mock_user) | |
46 | + mock_user.expects(:to_xml).returns('Generated XML') | |
47 | + get :index | |
48 | + assert_response :success | |
49 | + assert_equal 'Generated XML', @response.body | |
50 | + end | |
51 | +end | |
52 | + | |
53 | +class ShowActionBaseTest < ActionController::TestCase | |
54 | + include UserTestHelper | |
55 | + | |
56 | + def test_expose_the_resquested_user | |
57 | + User.expects(:find).with('42').returns(mock_user) | |
58 | + get :show, :id => '42' | |
59 | + assert_equal mock_user, assigns(:user) | |
60 | + end | |
61 | + | |
62 | + def test_controller_should_render_show | |
63 | + User.stubs(:find).returns(mock_user) | |
64 | + get :show | |
65 | + assert_response :success | |
66 | + assert_equal 'Show HTML', @response.body.strip | |
67 | + end | |
68 | + | |
69 | + def test_render_exposed_user_as_xml_when_mime_type_is_xml | |
70 | + @request.accept = 'application/xml' | |
71 | + User.expects(:find).with('42').returns(mock_user) | |
72 | + mock_user.expects(:to_xml).returns("Generated XML") | |
73 | + get :show, :id => '42' | |
74 | + assert_response :success | |
75 | + assert_equal 'Generated XML', @response.body | |
76 | + end | |
77 | +end | |
78 | + | |
79 | +class NewActionBaseTest < ActionController::TestCase | |
80 | + include UserTestHelper | |
81 | + | |
82 | + def test_expose_a_new_user | |
83 | + User.expects(:new).returns(mock_user) | |
84 | + get :new | |
85 | + assert_equal mock_user, assigns(:user) | |
86 | + end | |
87 | + | |
88 | + def test_controller_should_render_new | |
89 | + User.stubs(:new).returns(mock_user) | |
90 | + get :new | |
91 | + assert_response :success | |
92 | + assert_equal 'New HTML', @response.body.strip | |
93 | + end | |
94 | + | |
95 | + def test_render_exposed_a_new_user_as_xml_when_mime_type_is_xml | |
96 | + @request.accept = 'application/xml' | |
97 | + User.expects(:new).returns(mock_user) | |
98 | + mock_user.expects(:to_xml).returns("Generated XML") | |
99 | + get :new | |
100 | + assert_response :success | |
101 | + assert_equal 'Generated XML', @response.body | |
102 | + end | |
103 | +end | |
104 | + | |
105 | +class EditActionBaseTest < ActionController::TestCase | |
106 | + include UserTestHelper | |
107 | + | |
108 | + def test_expose_the_resquested_user | |
109 | + User.expects(:find).with('42').returns(mock_user) | |
110 | + get :edit, :id => '42' | |
111 | + assert_response :success | |
112 | + assert_equal mock_user, assigns(:user) | |
113 | + end | |
114 | + | |
115 | + def test_controller_should_render_edit | |
116 | + User.stubs(:find).returns(mock_user) | |
117 | + get :edit | |
118 | + assert_response :success | |
119 | + assert_equal 'Edit HTML', @response.body.strip | |
120 | + end | |
121 | +end | |
122 | + | |
123 | +class CreateActionBaseTest < ActionController::TestCase | |
124 | + include UserTestHelper | |
125 | + | |
126 | + def test_expose_a_newly_create_user_when_saved_with_success | |
127 | + User.expects(:new).with({'these' => 'params'}).returns(mock_user(:save => true)) | |
128 | + post :create, :user => {:these => 'params'} | |
129 | + assert_equal mock_user, assigns(:user) | |
130 | + end | |
131 | + | |
132 | + def test_redirect_to_the_created_user | |
133 | + User.stubs(:new).returns(mock_user(:save => true)) | |
134 | + @controller.expects(:resource_url).returns('http://test.host/').times(2) | |
135 | + post :create | |
136 | + assert_redirected_to 'http://test.host/' | |
137 | + end | |
138 | + | |
139 | + def test_show_flash_message_when_success | |
140 | + User.stubs(:new).returns(mock_user(:save => true)) | |
141 | + post :create | |
142 | + assert_equal flash[:notice], 'User was successfully created.' | |
143 | + end | |
144 | + | |
145 | + def test_render_new_template_when_user_cannot_be_saved | |
146 | + User.stubs(:new).returns(mock_user(:save => false, :errors => [])) | |
147 | + post :create | |
148 | + assert_response :success | |
149 | + assert_template :new | |
150 | + end | |
151 | + | |
152 | + def test_dont_show_flash_message_when_user_cannot_be_saved | |
153 | + User.stubs(:new).returns(mock_user(:save => false, :errors => [])) | |
154 | + post :create | |
155 | + assert flash.empty? | |
156 | + end | |
157 | +end | |
158 | + | |
159 | +class UpdateActionBaseTest < ActionController::TestCase | |
160 | + include UserTestHelper | |
161 | + | |
162 | + def test_update_the_requested_object | |
163 | + User.expects(:find).with('42').returns(mock_user) | |
164 | + mock_user.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
165 | + put :update, :id => '42', :user => {:these => 'params'} | |
166 | + assert_equal mock_user, assigns(:user) | |
167 | + end | |
168 | + | |
169 | + def test_redirect_to_the_created_user | |
170 | + User.stubs(:find).returns(mock_user(:update_attributes => true)) | |
171 | + @controller.expects(:resource_url).returns('http://test.host/') | |
172 | + put :update | |
173 | + assert_redirected_to 'http://test.host/' | |
174 | + end | |
175 | + | |
176 | + def test_show_flash_message_when_success | |
177 | + User.stubs(:find).returns(mock_user(:update_attributes => true)) | |
178 | + put :update | |
179 | + assert_equal flash[:notice], 'User was successfully updated.' | |
180 | + end | |
181 | + | |
182 | + def test_render_edit_template_when_user_cannot_be_saved | |
183 | + User.stubs(:find).returns(mock_user(:update_attributes => false, :errors => [])) | |
184 | + put :update | |
185 | + assert_response :success | |
186 | + assert_template :edit | |
187 | + end | |
188 | + | |
189 | + def test_dont_show_flash_message_when_user_cannot_be_saved | |
190 | + User.stubs(:find).returns(mock_user(:update_attributes => false, :errors => [])) | |
191 | + put :update | |
192 | + assert flash.empty? | |
193 | + end | |
194 | +end | |
195 | + | |
196 | +class DestroyActionBaseTest < ActionController::TestCase | |
197 | + include UserTestHelper | |
198 | + | |
199 | + def test_the_resquested_user_is_destroyed | |
200 | + User.expects(:find).with('42').returns(mock_user) | |
201 | + mock_user.expects(:destroy) | |
202 | + delete :destroy, :id => '42' | |
203 | + assert_equal mock_user, assigns(:user) | |
204 | + end | |
205 | + | |
206 | + def test_show_flash_message | |
207 | + User.stubs(:find).returns(mock_user(:destroy => true)) | |
208 | + delete :destroy | |
209 | + assert_equal flash[:notice], 'User was successfully destroyed.' | |
210 | + end | |
211 | + | |
212 | + def test_redirects_to_users_list | |
213 | + User.stubs(:find).returns(mock_user(:destroy => true)) | |
214 | + @controller.expects(:collection_url).returns('http://test.host/') | |
215 | + delete :destroy | |
216 | + assert_redirected_to 'http://test.host/' | |
217 | + end | |
218 | +end | |
219 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/belongs_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,87 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Post | |
4 | +end | |
5 | + | |
6 | +class Comment | |
7 | + def self.human_name; 'Comment'; end | |
8 | +end | |
9 | + | |
10 | +class CommentsController < InheritedResources::Base | |
11 | + belongs_to :post | |
12 | +end | |
13 | + | |
14 | +class BelongsToTest < ActionController::TestCase | |
15 | + tests CommentsController | |
16 | + | |
17 | + def setup | |
18 | + Post.expects(:find).with('37').returns(mock_post) | |
19 | + mock_post.expects(:comments).returns(Comment) | |
20 | + | |
21 | + @controller.stubs(:resource_url).returns('/') | |
22 | + @controller.stubs(:collection_url).returns('/') | |
23 | + end | |
24 | + | |
25 | + def test_expose_all_comments_as_instance_variable_on_index | |
26 | + Comment.expects(:find).with(:all).returns([mock_comment]) | |
27 | + get :index, :post_id => '37' | |
28 | + assert_equal mock_post, assigns(:post) | |
29 | + assert_equal [mock_comment], assigns(:comments) | |
30 | + end | |
31 | + | |
32 | + def test_expose_the_resquested_comment_on_show | |
33 | + Comment.expects(:find).with('42').returns(mock_comment) | |
34 | + get :show, :id => '42', :post_id => '37' | |
35 | + assert_equal mock_post, assigns(:post) | |
36 | + assert_equal mock_comment, assigns(:comment) | |
37 | + end | |
38 | + | |
39 | + def test_expose_a_new_comment_on_new | |
40 | + Comment.expects(:build).returns(mock_comment) | |
41 | + get :new, :post_id => '37' | |
42 | + assert_equal mock_post, assigns(:post) | |
43 | + assert_equal mock_comment, assigns(:comment) | |
44 | + end | |
45 | + | |
46 | + def test_expose_the_resquested_comment_on_edit | |
47 | + Comment.expects(:find).with('42').returns(mock_comment) | |
48 | + get :edit, :id => '42', :post_id => '37' | |
49 | + assert_equal mock_post, assigns(:post) | |
50 | + assert_equal mock_comment, assigns(:comment) | |
51 | + end | |
52 | + | |
53 | + def test_expose_a_newly_create_comment_on_create | |
54 | + Comment.expects(:build).with({'these' => 'params'}).returns(mock_comment(:save => true)) | |
55 | + post :create, :post_id => '37', :comment => {:these => 'params'} | |
56 | + assert_equal mock_post, assigns(:post) | |
57 | + assert_equal mock_comment, assigns(:comment) | |
58 | + end | |
59 | + | |
60 | + def test_update_the_requested_object_on_update | |
61 | + Comment.expects(:find).with('42').returns(mock_comment) | |
62 | + mock_comment.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
63 | + put :update, :id => '42', :post_id => '37', :comment => {:these => 'params'} | |
64 | + assert_equal mock_post, assigns(:post) | |
65 | + assert_equal mock_comment, assigns(:comment) | |
66 | + end | |
67 | + | |
68 | + def test_the_resquested_comment_is_destroyed_on_destroy | |
69 | + Comment.expects(:find).with('42').returns(mock_comment) | |
70 | + mock_comment.expects(:destroy) | |
71 | + delete :destroy, :id => '42', :post_id => '37' | |
72 | + assert_equal mock_post, assigns(:post) | |
73 | + assert_equal mock_comment, assigns(:comment) | |
74 | + end | |
75 | + | |
76 | + protected | |
77 | + | |
78 | + def mock_post(stubs={}) | |
79 | + @mock_post ||= mock(stubs) | |
80 | + end | |
81 | + | |
82 | + def mock_comment(stubs={}) | |
83 | + @mock_comment ||= mock(stubs) | |
84 | + end | |
85 | + | |
86 | +end | |
87 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/class_methods_test.rb
0 → 100644
... | ... | @@ -0,0 +1,137 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Book; end | |
4 | +class Folder; end | |
5 | + | |
6 | +class BooksController < InheritedResources::Base | |
7 | + actions :index, :show | |
8 | +end | |
9 | + | |
10 | +class ReadersController < InheritedResources::Base | |
11 | + actions :all, :except => [ :edit, :update ] | |
12 | +end | |
13 | + | |
14 | +class FoldersController < InheritedResources::Base | |
15 | +end | |
16 | + | |
17 | +class Dean | |
18 | + def self.human_name; 'Dean'; end | |
19 | +end | |
20 | + | |
21 | +class SchoolsController < InheritedResources::Base | |
22 | + has_scope :by_city | |
23 | + has_scope :featured, :boolean => true, :only => :index, :key => :by_featured | |
24 | +end | |
25 | + | |
26 | +class DeansController < InheritedResources::Base | |
27 | + belongs_to :school | |
28 | +end | |
29 | + | |
30 | + | |
31 | +class ActionsClassMethodTest < ActiveSupport::TestCase | |
32 | + def test_actions_are_undefined | |
33 | + action_methods = BooksController.send(:action_methods) | |
34 | + assert_equal 2, action_methods.size | |
35 | + | |
36 | + ['index', 'show'].each do |action| | |
37 | + assert action_methods.include? action | |
38 | + end | |
39 | + end | |
40 | + | |
41 | + def test_actions_are_undefined_when_except_option_is_given | |
42 | + action_methods = ReadersController.send(:action_methods) | |
43 | + assert_equal 5, action_methods.size | |
44 | + | |
45 | + ['index', 'new', 'show', 'create', 'destroy'].each do |action| | |
46 | + assert action_methods.include? action | |
47 | + end | |
48 | + end | |
49 | +end | |
50 | + | |
51 | + | |
52 | +class DefaultsClassMethodTest < ActiveSupport::TestCase | |
53 | + def test_resource_class_is_set_to_nil_when_resource_model_cannot_be_found | |
54 | + assert_nil ReadersController.send(:resource_class) | |
55 | + end | |
56 | + | |
57 | + def test_defaults_are_set | |
58 | + assert Folder, FoldersController.send(:resource_class) | |
59 | + assert :folder, FoldersController.send(:resources_configuration)[:self][:instance_name] | |
60 | + assert :folders, FoldersController.send(:resources_configuration)[:self][:collection_name] | |
61 | + end | |
62 | + | |
63 | + def test_defaults_can_be_overwriten | |
64 | + BooksController.send(:defaults, :resource_class => String, :instance_name => 'string', :collection_name => 'strings') | |
65 | + | |
66 | + assert String, BooksController.send(:resource_class) | |
67 | + assert :string, BooksController.send(:resources_configuration)[:self][:instance_name] | |
68 | + assert :strings, BooksController.send(:resources_configuration)[:self][:collection_name] | |
69 | + | |
70 | + BooksController.send(:defaults, :class_name => 'Fixnum', :instance_name => :fixnum, :collection_name => :fixnums) | |
71 | + | |
72 | + assert String, BooksController.send(:resource_class) | |
73 | + assert :string, BooksController.send(:resources_configuration)[:self][:instance_name] | |
74 | + assert :strings, BooksController.send(:resources_configuration)[:self][:collection_name] | |
75 | + end | |
76 | + | |
77 | + def test_defaults_raises_invalid_key | |
78 | + assert_raise ArgumentError do | |
79 | + BooksController.send(:defaults, :boom => String) | |
80 | + end | |
81 | + end | |
82 | + | |
83 | + def test_url_helpers_are_recreated_when_defaults_change | |
84 | + BooksController.expects(:create_resources_url_helpers!).returns(true).once | |
85 | + BooksController.send(:defaults, :instance_name => 'string', :collection_name => 'strings') | |
86 | + end | |
87 | +end | |
88 | + | |
89 | +class BelongsToErrorsTest < ActiveSupport::TestCase | |
90 | + def test_belongs_to_raise_errors_with_invalid_arguments | |
91 | + assert_raise ArgumentError do | |
92 | + DeansController.send(:belongs_to) | |
93 | + end | |
94 | + | |
95 | + assert_raise ArgumentError do | |
96 | + DeansController.send(:belongs_to, :nice, :invalid_key => '') | |
97 | + end | |
98 | + end | |
99 | + | |
100 | + def test_belongs_to_raises_an_error_when_multiple_associations_are_given_with_options | |
101 | + assert_raise ArgumentError do | |
102 | + DeansController.send(:belongs_to, :arguments, :with_options, :parent_class => Professor) | |
103 | + end | |
104 | + end | |
105 | + | |
106 | + def test_url_helpers_are_recreated_just_once_when_belongs_to_is_called_with_block | |
107 | + DeansController.expects(:create_resources_url_helpers!).returns(true).once | |
108 | + DeansController.send(:belongs_to, :school) do | |
109 | + belongs_to :association | |
110 | + end | |
111 | + ensure | |
112 | + DeansController.send(:parents_symbols=, [:school]) | |
113 | + end | |
114 | + | |
115 | + def test_url_helpers_are_recreated_just_once_when_belongs_to_is_called_with_multiple_blocks | |
116 | + DeansController.expects(:create_resources_url_helpers!).returns(true).once | |
117 | + DeansController.send(:belongs_to, :school) do | |
118 | + belongs_to :association do | |
119 | + belongs_to :nested | |
120 | + end | |
121 | + end | |
122 | + ensure | |
123 | + DeansController.send(:parents_symbols=, [:school]) | |
124 | + end | |
125 | +end | |
126 | + | |
127 | +class HasScopeClassMethods < ActiveSupport::TestCase | |
128 | + def test_scope_configuration_is_stored_as_hashes | |
129 | + config = SchoolsController.send(:scopes_configuration) | |
130 | + | |
131 | + assert config.key?(:by_city) | |
132 | + assert config.key?(:featured) | |
133 | + | |
134 | + assert_equal config[:by_city], { :key => :by_city, :only => [], :except => [] } | |
135 | + assert_equal config[:featured], { :key => :by_featured, :only => [ :index ], :except => [], :boolean => true } | |
136 | + end | |
137 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/customized_belongs_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,76 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class GreatSchool | |
4 | +end | |
5 | + | |
6 | +class Professor | |
7 | + def self.human_name; 'Professor'; end | |
8 | +end | |
9 | + | |
10 | +class ProfessorsController < InheritedResources::Base | |
11 | + belongs_to :school, :parent_class => GreatSchool, :instance_name => :great_school, | |
12 | + :finder => :find_by_title!, :param => :school_title | |
13 | +end | |
14 | + | |
15 | +class CustomizedBelongsToTest < ActionController::TestCase | |
16 | + tests ProfessorsController | |
17 | + | |
18 | + def setup | |
19 | + GreatSchool.expects(:find_by_title!).with('nice').returns(mock_school(:professors => Professor)) | |
20 | + @controller.stubs(:resource_url).returns('/') | |
21 | + @controller.stubs(:collection_url).returns('/') | |
22 | + end | |
23 | + | |
24 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_index | |
25 | + Professor.stubs(:find).returns([mock_professor]) | |
26 | + get :index, :school_title => 'nice' | |
27 | + assert_equal mock_school, assigns(:great_school) | |
28 | + end | |
29 | + | |
30 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_show | |
31 | + Professor.stubs(:find).returns(mock_professor) | |
32 | + get :show, :school_title => 'nice' | |
33 | + assert_equal mock_school, assigns(:great_school) | |
34 | + end | |
35 | + | |
36 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_new | |
37 | + Professor.stubs(:build).returns(mock_professor) | |
38 | + get :new, :school_title => 'nice' | |
39 | + assert_equal mock_school, assigns(:great_school) | |
40 | + end | |
41 | + | |
42 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_edit | |
43 | + Professor.stubs(:find).returns(mock_professor) | |
44 | + get :edit, :school_title => 'nice' | |
45 | + assert_equal mock_school, assigns(:great_school) | |
46 | + end | |
47 | + | |
48 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_create | |
49 | + Professor.stubs(:build).returns(mock_professor(:save => true)) | |
50 | + post :create, :school_title => 'nice' | |
51 | + assert_equal mock_school, assigns(:great_school) | |
52 | + end | |
53 | + | |
54 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_update | |
55 | + Professor.stubs(:find).returns(mock_professor(:update_attributes => true)) | |
56 | + put :update, :school_title => 'nice' | |
57 | + assert_equal mock_school, assigns(:great_school) | |
58 | + end | |
59 | + | |
60 | + def test_expose_the_resquested_school_with_chosen_instance_variable_on_destroy | |
61 | + Professor.stubs(:find).returns(mock_professor(:destroy => true)) | |
62 | + delete :destroy, :school_title => 'nice' | |
63 | + assert_equal mock_school, assigns(:great_school) | |
64 | + end | |
65 | + | |
66 | + protected | |
67 | + | |
68 | + def mock_school(stubs={}) | |
69 | + @mock_school ||= mock(stubs) | |
70 | + end | |
71 | + | |
72 | + def mock_professor(stubs={}) | |
73 | + @mock_professor ||= mock(stubs) | |
74 | + end | |
75 | +end | |
76 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/defaults_test.rb
0 → 100644
... | ... | @@ -0,0 +1,70 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Malarz | |
4 | + def self.human_name; 'Painter'; end | |
5 | +end | |
6 | + | |
7 | +class PaintersController < InheritedResources::Base | |
8 | + defaults :instance_name => 'malarz', :collection_name => 'malarze', | |
9 | + :resource_class => Malarz, :route_prefix => nil | |
10 | +end | |
11 | + | |
12 | +class DefaultsTest < ActionController::TestCase | |
13 | + tests PaintersController | |
14 | + | |
15 | + def setup | |
16 | + @controller.stubs(:resource_url).returns('/') | |
17 | + @controller.stubs(:collection_url).returns('/') | |
18 | + end | |
19 | + | |
20 | + def test_expose_all_painters_as_instance_variable | |
21 | + Malarz.expects(:find).with(:all).returns([mock_painter]) | |
22 | + get :index | |
23 | + assert_equal [mock_painter], assigns(:malarze) | |
24 | + end | |
25 | + | |
26 | + def test_expose_the_resquested_painter_on_show | |
27 | + Malarz.expects(:find).with('42').returns(mock_painter) | |
28 | + get :show, :id => '42' | |
29 | + assert_equal mock_painter, assigns(:malarz) | |
30 | + end | |
31 | + | |
32 | + def test_expose_a_new_painter | |
33 | + Malarz.expects(:new).returns(mock_painter) | |
34 | + get :new | |
35 | + assert_equal mock_painter, assigns(:malarz) | |
36 | + end | |
37 | + | |
38 | + def test_expose_the_resquested_painter_on_edit | |
39 | + Malarz.expects(:find).with('42').returns(mock_painter) | |
40 | + get :edit, :id => '42' | |
41 | + assert_response :success | |
42 | + assert_equal mock_painter, assigns(:malarz) | |
43 | + end | |
44 | + | |
45 | + def test_expose_a_newly_create_painter_when_saved_with_success | |
46 | + Malarz.expects(:new).with({'these' => 'params'}).returns(mock_painter(:save => true)) | |
47 | + post :create, :malarz => {:these => 'params'} | |
48 | + assert_equal mock_painter, assigns(:malarz) | |
49 | + end | |
50 | + | |
51 | + def test_update_the_requested_object | |
52 | + Malarz.expects(:find).with('42').returns(mock_painter) | |
53 | + mock_painter.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
54 | + put :update, :id => '42', :malarz => {:these => 'params'} | |
55 | + assert_equal mock_painter, assigns(:malarz) | |
56 | + end | |
57 | + | |
58 | + def test_the_resquested_painter_is_destroyed | |
59 | + Malarz.expects(:find).with('42').returns(mock_painter) | |
60 | + mock_painter.expects(:destroy) | |
61 | + delete :destroy, :id => '42' | |
62 | + assert_equal mock_painter, assigns(:malarz) | |
63 | + end | |
64 | + | |
65 | + protected | |
66 | + def mock_painter(stubs={}) | |
67 | + @mock_painter ||= mock(stubs) | |
68 | + end | |
69 | +end | |
70 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/flash_test.rb
0 → 100644
... | ... | @@ -0,0 +1,83 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Address | |
4 | + def self.human_name; 'Address'; end | |
5 | +end | |
6 | + | |
7 | +class AddressesController < InheritedResources::Base | |
8 | + protected | |
9 | + def interpolation_options | |
10 | + { :reference => 'Ocean Avenue' } | |
11 | + end | |
12 | +end | |
13 | + | |
14 | +module Admin; end | |
15 | +class Admin::AddressesController < InheritedResources::Base | |
16 | + protected | |
17 | + def interpolation_options | |
18 | + { :reference => 'Ocean Avenue' } | |
19 | + end | |
20 | +end | |
21 | + | |
22 | +class FlashBaseHelpersTest < ActionController::TestCase | |
23 | + tests AddressesController | |
24 | + | |
25 | + def setup | |
26 | + @request.accept = 'application/xml' | |
27 | + end | |
28 | + | |
29 | + def test_success_flash_message_on_create_with_yml | |
30 | + Address.stubs(:new).returns(mock_address(:save => true)) | |
31 | + @controller.stubs(:address_url) | |
32 | + post :create | |
33 | + assert_equal 'You created a new address close to <b>Ocean Avenue</b>.', flash[:notice] | |
34 | + end | |
35 | + | |
36 | + def test_success_flash_message_on_create_with_namespaced_controller | |
37 | + @controller = Admin::AddressesController.new | |
38 | + Address.stubs(:new).returns(mock_address(:save => true)) | |
39 | + @controller.stubs(:address_url) | |
40 | + post :create | |
41 | + assert_equal 'Admin, you created a new address close to <b>Ocean Avenue</b>.', flash[:notice] | |
42 | + end | |
43 | + | |
44 | + def test_failure_flash_message_on_create_with_namespaced_controller_actions | |
45 | + @controller = Admin::AddressesController.new | |
46 | + Address.stubs(:new).returns(mock_address(:save => false)) | |
47 | + @controller.stubs(:address_url) | |
48 | + post :create | |
49 | + assert_equal 'Admin error message.', flash[:error] | |
50 | + end | |
51 | + | |
52 | + def test_inherited_success_flash_message_on_update_on_namespaced_controllers | |
53 | + @controller = Admin::AddressesController.new | |
54 | + Address.stubs(:find).returns(mock_address(:update_attributes => true)) | |
55 | + put :update | |
56 | + assert_response :success | |
57 | + assert_equal 'Nice! Address was updated with success!', flash[:notice] | |
58 | + end | |
59 | + | |
60 | + def test_success_flash_message_on_update | |
61 | + Address.stubs(:find).returns(mock_address(:update_attributes => true)) | |
62 | + put :update | |
63 | + assert_response :success | |
64 | + assert_equal 'Nice! Address was updated with success!', flash[:notice] | |
65 | + end | |
66 | + | |
67 | + def test_failure_flash_message_on_update | |
68 | + Address.stubs(:find).returns(mock_address(:update_attributes => false, :errors => [])) | |
69 | + put :update | |
70 | + assert_equal 'Oh no! We could not update your address!', flash[:error] | |
71 | + end | |
72 | + | |
73 | + def test_success_flash_message_on_destroy | |
74 | + Address.stubs(:find).returns(mock_address(:destroy => true)) | |
75 | + delete :destroy | |
76 | + assert_equal 'Address was successfully destroyed.', flash[:notice] | |
77 | + end | |
78 | + | |
79 | + protected | |
80 | + def mock_address(stubs={}) | |
81 | + @mock_address ||= mock(stubs) | |
82 | + end | |
83 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/has_scope_test.rb
0 → 100644
... | ... | @@ -0,0 +1,112 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Tree | |
4 | + def self.human_name; 'Tree'; end | |
5 | +end | |
6 | + | |
7 | +class TreesController < InheritedResources::Base | |
8 | + has_scope :color | |
9 | + has_scope :only_tall, :boolean => true, :only => :index | |
10 | + has_scope :shadown_range, :default => 10, :except => [ :index, :show, :destroy, :new ] | |
11 | + has_scope :root_type, :key => :root | |
12 | + has_scope :calculate_height, :default => proc {|c| c.session[:height] || 20 }, :only => :new | |
13 | +end | |
14 | + | |
15 | +class HasScopeTest < ActionController::TestCase | |
16 | + tests TreesController | |
17 | + | |
18 | + def setup | |
19 | + @controller.stubs(:resource_url).returns('/') | |
20 | + @controller.stubs(:collection_url).returns('/') | |
21 | + end | |
22 | + | |
23 | + def test_boolean_scope_is_called_when_boolean_param_is_true | |
24 | + Tree.expects(:only_tall).with().returns(Tree).in_sequence | |
25 | + Tree.expects(:find).with(:all).returns([mock_tree]).in_sequence | |
26 | + get :index, :only_tall => 'true' | |
27 | + assert_equal([mock_tree], assigns(:trees)) | |
28 | + assert_equal({ :only_tall => 'true' }, assigns(:current_scopes)) | |
29 | + end | |
30 | + | |
31 | + def test_boolean_scope_is_called_when_boolean_param_is_false | |
32 | + Tree.expects(:only_tall).never | |
33 | + Tree.expects(:find).with(:all).returns([mock_tree]) | |
34 | + get :index, :only_tall => 'false' | |
35 | + assert_equal([mock_tree], assigns(:trees)) | |
36 | + assert_equal({ :only_tall => 'false' }, assigns(:current_scopes)) | |
37 | + end | |
38 | + | |
39 | + def test_scope_is_called_only_on_index | |
40 | + Tree.expects(:only_tall).never | |
41 | + Tree.expects(:find).with('42').returns(mock_tree) | |
42 | + get :show, :only_tall => 'true', :id => '42' | |
43 | + assert_equal(mock_tree, assigns(:tree)) | |
44 | + assert_equal({ }, assigns(:current_scopes)) | |
45 | + end | |
46 | + | |
47 | + def test_scope_is_called_except_on_index | |
48 | + Tree.expects(:shadown_range).with().never | |
49 | + Tree.expects(:find).with(:all).returns([mock_tree]) | |
50 | + get :index, :shadown_range => 20 | |
51 | + assert_equal([mock_tree], assigns(:trees)) | |
52 | + assert_equal({ }, assigns(:current_scopes)) | |
53 | + end | |
54 | + | |
55 | + def test_scope_is_called_with_arguments | |
56 | + Tree.expects(:color).with('blue').returns(Tree).in_sequence | |
57 | + Tree.expects(:find).with(:all).returns([mock_tree]).in_sequence | |
58 | + get :index, :color => 'blue' | |
59 | + assert_equal([mock_tree], assigns(:trees)) | |
60 | + assert_equal({ :color => 'blue' }, assigns(:current_scopes)) | |
61 | + end | |
62 | + | |
63 | + def test_multiple_scopes_are_called | |
64 | + Tree.expects(:only_tall).with().returns(Tree) | |
65 | + Tree.expects(:color).with('blue').returns(Tree) | |
66 | + Tree.expects(:find).with(:all).returns([mock_tree]) | |
67 | + get :index, :color => 'blue', :only_tall => 'true' | |
68 | + assert_equal([mock_tree], assigns(:trees)) | |
69 | + assert_equal({ :color => 'blue', :only_tall => 'true' }, assigns(:current_scopes)) | |
70 | + end | |
71 | + | |
72 | + def test_scope_is_called_with_default_value | |
73 | + Tree.expects(:shadown_range).with(10).returns(Tree).in_sequence | |
74 | + Tree.expects(:find).with('42').returns(mock_tree).in_sequence | |
75 | + get :edit, :id => '42' | |
76 | + assert_equal(mock_tree, assigns(:tree)) | |
77 | + assert_equal({ :shadown_range => 10 }, assigns(:current_scopes)) | |
78 | + end | |
79 | + | |
80 | + def test_default_scope_value_can_be_overwritten | |
81 | + Tree.expects(:shadown_range).with('20').returns(Tree).in_sequence | |
82 | + Tree.expects(:find).with('42').returns(mock_tree).in_sequence | |
83 | + get :edit, :id => '42', :shadown_range => '20' | |
84 | + assert_equal(mock_tree, assigns(:tree)) | |
85 | + assert_equal({ :shadown_range => '20' }, assigns(:current_scopes)) | |
86 | + end | |
87 | + | |
88 | + def test_scope_with_different_key | |
89 | + Tree.expects(:root_type).with('outside').returns(Tree).in_sequence | |
90 | + Tree.expects(:find).with('42').returns(mock_tree).in_sequence | |
91 | + get :show, :id => '42', :root => 'outside' | |
92 | + assert_equal(mock_tree, assigns(:tree)) | |
93 | + assert_equal({ :root => 'outside' }, assigns(:current_scopes)) | |
94 | + end | |
95 | + | |
96 | + def test_scope_with_default_value_as_proc | |
97 | + session[:height] = 100 | |
98 | + Tree.expects(:calculate_height).with(100).returns(Tree).in_sequence | |
99 | + Tree.expects(:new).returns(mock_tree).in_sequence | |
100 | + get :new | |
101 | + assert_equal(mock_tree, assigns(:tree)) | |
102 | + assert_equal({ :calculate_height => 100 }, assigns(:current_scopes)) | |
103 | + end | |
104 | + | |
105 | + protected | |
106 | + | |
107 | + def mock_tree(stubs={}) | |
108 | + @mock_tree ||= mock(stubs) | |
109 | + end | |
110 | + | |
111 | +end | |
112 | + | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/nested_belongs_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,108 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Country | |
4 | +end | |
5 | + | |
6 | +class State | |
7 | +end | |
8 | + | |
9 | +class City | |
10 | + def self.human_name; 'City'; end | |
11 | +end | |
12 | + | |
13 | +class CitiesController < InheritedResources::Base | |
14 | + belongs_to :country, :state | |
15 | +end | |
16 | + | |
17 | +class NestedBelongsToTest < ActionController::TestCase | |
18 | + tests CitiesController | |
19 | + | |
20 | + def setup | |
21 | + Country.expects(:find).with('13').returns(mock_country) | |
22 | + mock_country.expects(:states).returns(State) | |
23 | + State.expects(:find).with('37').returns(mock_state) | |
24 | + mock_state.expects(:cities).returns(City) | |
25 | + | |
26 | + @controller.stubs(:resource_url).returns('/') | |
27 | + @controller.stubs(:collection_url).returns('/') | |
28 | + end | |
29 | + | |
30 | + def test_assigns_country_and_state_and_city_on_create | |
31 | + City.expects(:find).with(:all).returns([mock_city]) | |
32 | + get :index, :state_id => '37', :country_id => '13' | |
33 | + | |
34 | + assert_equal mock_country, assigns(:country) | |
35 | + assert_equal mock_state, assigns(:state) | |
36 | + assert_equal [mock_city], assigns(:cities) | |
37 | + end | |
38 | + | |
39 | + def test_assigns_country_and_state_and_city_on_show | |
40 | + City.expects(:find).with('42').returns(mock_city) | |
41 | + get :show, :id => '42', :state_id => '37', :country_id => '13' | |
42 | + | |
43 | + assert_equal mock_country, assigns(:country) | |
44 | + assert_equal mock_state, assigns(:state) | |
45 | + assert_equal mock_city, assigns(:city) | |
46 | + end | |
47 | + | |
48 | + def test_assigns_country_and_state_and_city_on_new | |
49 | + City.expects(:build).returns(mock_city) | |
50 | + get :new, :state_id => '37', :country_id => '13' | |
51 | + | |
52 | + assert_equal mock_country, assigns(:country) | |
53 | + assert_equal mock_state, assigns(:state) | |
54 | + assert_equal mock_city, assigns(:city) | |
55 | + end | |
56 | + | |
57 | + def test_assigns_country_and_state_and_city_on_edit | |
58 | + City.expects(:find).with('42').returns(mock_city) | |
59 | + get :edit, :id => '42', :state_id => '37', :country_id => '13' | |
60 | + | |
61 | + assert_equal mock_country, assigns(:country) | |
62 | + assert_equal mock_state, assigns(:state) | |
63 | + assert_equal mock_city, assigns(:city) | |
64 | + end | |
65 | + | |
66 | + def test_assigns_country_and_state_and_city_on_create | |
67 | + City.expects(:build).with({'these' => 'params'}).returns(mock_city) | |
68 | + mock_city.expects(:save).returns(true) | |
69 | + post :create, :state_id => '37', :country_id => '13', :city => {:these => 'params'} | |
70 | + | |
71 | + assert_equal mock_country, assigns(:country) | |
72 | + assert_equal mock_state, assigns(:state) | |
73 | + assert_equal mock_city, assigns(:city) | |
74 | + end | |
75 | + | |
76 | + def test_assigns_country_and_state_and_city_on_update | |
77 | + City.expects(:find).with('42').returns(mock_city) | |
78 | + mock_city.expects(:update_attributes).returns(true) | |
79 | + put :update, :id => '42', :state_id => '37', :country_id => '13', :city => {:these => 'params'} | |
80 | + | |
81 | + assert_equal mock_country, assigns(:country) | |
82 | + assert_equal mock_state, assigns(:state) | |
83 | + assert_equal mock_city, assigns(:city) | |
84 | + end | |
85 | + | |
86 | + def test_assigns_country_and_state_and_city_on_destroy | |
87 | + City.expects(:find).with('42').returns(mock_city) | |
88 | + mock_city.expects(:destroy) | |
89 | + delete :destroy, :id => '42', :state_id => '37', :country_id => '13' | |
90 | + | |
91 | + assert_equal mock_country, assigns(:country) | |
92 | + assert_equal mock_state, assigns(:state) | |
93 | + assert_equal mock_city, assigns(:city) | |
94 | + end | |
95 | + | |
96 | + protected | |
97 | + def mock_country(stubs={}) | |
98 | + @mock_country ||= mock(stubs) | |
99 | + end | |
100 | + | |
101 | + def mock_state(stubs={}) | |
102 | + @mock_state ||= mock(stubs) | |
103 | + end | |
104 | + | |
105 | + def mock_city(stubs={}) | |
106 | + @mock_city ||= mock(stubs) | |
107 | + end | |
108 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/optional_belongs_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,164 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Brands; end | |
4 | +class Category; end | |
5 | + | |
6 | +class Product | |
7 | + def self.human_name; 'Product'; end | |
8 | +end | |
9 | + | |
10 | +class ProductsController < InheritedResources::Base | |
11 | + belongs_to :brand, :category, :polymorphic => true, :optional => true | |
12 | +end | |
13 | + | |
14 | +class OptionalTest < ActionController::TestCase | |
15 | + tests ProductsController | |
16 | + | |
17 | + def setup | |
18 | + @controller.stubs(:resource_url).returns('/') | |
19 | + @controller.stubs(:collection_url).returns('/') | |
20 | + end | |
21 | + | |
22 | + def test_expose_all_products_as_instance_variable_with_category | |
23 | + Category.expects(:find).with('37').returns(mock_category) | |
24 | + mock_category.expects(:products).returns(Product) | |
25 | + Product.expects(:find).with(:all).returns([mock_product]) | |
26 | + get :index, :category_id => '37' | |
27 | + assert_equal mock_category, assigns(:category) | |
28 | + assert_equal [mock_product], assigns(:products) | |
29 | + end | |
30 | + | |
31 | + def test_expose_all_products_as_instance_variable_without_category | |
32 | + Product.expects(:find).with(:all).returns([mock_product]) | |
33 | + get :index | |
34 | + assert_equal nil, assigns(:category) | |
35 | + assert_equal [mock_product], assigns(:products) | |
36 | + end | |
37 | + | |
38 | + def test_expose_the_resquested_product_with_category | |
39 | + Category.expects(:find).with('37').returns(mock_category) | |
40 | + mock_category.expects(:products).returns(Product) | |
41 | + Product.expects(:find).with('42').returns(mock_product) | |
42 | + get :show, :id => '42', :category_id => '37' | |
43 | + assert_equal mock_category, assigns(:category) | |
44 | + assert_equal mock_product, assigns(:product) | |
45 | + end | |
46 | + | |
47 | + def test_expose_the_resquested_product_without_category | |
48 | + Product.expects(:find).with('42').returns(mock_product) | |
49 | + get :show, :id => '42' | |
50 | + assert_equal nil, assigns(:category) | |
51 | + assert_equal mock_product, assigns(:product) | |
52 | + end | |
53 | + | |
54 | + def test_expose_a_new_product_with_category | |
55 | + Category.expects(:find).with('37').returns(mock_category) | |
56 | + mock_category.expects(:products).returns(Product) | |
57 | + Product.expects(:build).returns(mock_product) | |
58 | + get :new, :category_id => '37' | |
59 | + assert_equal mock_category, assigns(:category) | |
60 | + assert_equal mock_product, assigns(:product) | |
61 | + end | |
62 | + | |
63 | + def test_expose_a_new_product_without_category | |
64 | + Product.expects(:new).returns(mock_product) | |
65 | + get :new | |
66 | + assert_equal nil, assigns(:category) | |
67 | + assert_equal mock_product, assigns(:product) | |
68 | + end | |
69 | + | |
70 | + def test_expose_the_resquested_product_for_edition_with_category | |
71 | + Category.expects(:find).with('37').returns(mock_category) | |
72 | + mock_category.expects(:products).returns(Product) | |
73 | + Product.expects(:find).with('42').returns(mock_product) | |
74 | + get :edit, :id => '42', :category_id => '37' | |
75 | + assert_equal mock_category, assigns(:category) | |
76 | + assert_equal mock_product, assigns(:product) | |
77 | + end | |
78 | + | |
79 | + def test_expose_the_resquested_product_for_edition_without_category | |
80 | + Product.expects(:find).with('42').returns(mock_product) | |
81 | + get :edit, :id => '42' | |
82 | + assert_equal nil, assigns(:category) | |
83 | + assert_equal mock_product, assigns(:product) | |
84 | + end | |
85 | + | |
86 | + def test_expose_a_newly_create_product_with_category | |
87 | + Category.expects(:find).with('37').returns(mock_category) | |
88 | + mock_category.expects(:products).returns(Product) | |
89 | + Product.expects(:build).with({'these' => 'params'}).returns(mock_product(:save => true)) | |
90 | + post :create, :category_id => '37', :product => {:these => 'params'} | |
91 | + assert_equal mock_category, assigns(:category) | |
92 | + assert_equal mock_product, assigns(:product) | |
93 | + end | |
94 | + | |
95 | + def test_expose_a_newly_create_product_without_category | |
96 | + Product.expects(:new).with({'these' => 'params'}).returns(mock_product(:save => true)) | |
97 | + post :create, :product => {:these => 'params'} | |
98 | + assert_equal nil, assigns(:category) | |
99 | + assert_equal mock_product, assigns(:product) | |
100 | + end | |
101 | + | |
102 | + def test_update_the_requested_object_with_category | |
103 | + Category.expects(:find).with('37').returns(mock_category) | |
104 | + mock_category.expects(:products).returns(Product) | |
105 | + Product.expects(:find).with('42').returns(mock_product) | |
106 | + mock_product.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
107 | + | |
108 | + put :update, :id => '42', :category_id => '37', :product => {:these => 'params'} | |
109 | + assert_equal mock_category, assigns(:category) | |
110 | + assert_equal mock_product, assigns(:product) | |
111 | + end | |
112 | + | |
113 | + def test_update_the_requested_object_without_category | |
114 | + Product.expects(:find).with('42').returns(mock_product) | |
115 | + mock_product.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
116 | + | |
117 | + put :update, :id => '42', :product => {:these => 'params'} | |
118 | + assert_equal nil, assigns(:category) | |
119 | + assert_equal mock_product, assigns(:product) | |
120 | + end | |
121 | + | |
122 | + def test_the_resquested_product_is_destroyed_with_category | |
123 | + Category.expects(:find).with('37').returns(mock_category) | |
124 | + mock_category.expects(:products).returns(Product) | |
125 | + Product.expects(:find).with('42').returns(mock_product) | |
126 | + mock_product.expects(:destroy) | |
127 | + @controller.expects(:collection_url).returns('/') | |
128 | + | |
129 | + delete :destroy, :id => '42', :category_id => '37' | |
130 | + assert_equal mock_category, assigns(:category) | |
131 | + assert_equal mock_product, assigns(:product) | |
132 | + end | |
133 | + | |
134 | + def test_the_resquested_product_is_destroyed_without_category | |
135 | + Product.expects(:find).with('42').returns(mock_product) | |
136 | + mock_product.expects(:destroy) | |
137 | + @controller.expects(:collection_url).returns('/') | |
138 | + | |
139 | + delete :destroy, :id => '42' | |
140 | + assert_equal nil, assigns(:category) | |
141 | + assert_equal mock_product, assigns(:product) | |
142 | + end | |
143 | + | |
144 | + def test_polymorphic_helpers | |
145 | + Product.expects(:find).with(:all).returns([mock_product]) | |
146 | + get :index | |
147 | + | |
148 | + assert !@controller.send(:parent?) | |
149 | + assert_equal nil, assigns(:parent_type) | |
150 | + assert_equal nil, @controller.send(:parent_type) | |
151 | + assert_equal nil, @controller.send(:parent_class) | |
152 | + assert_equal nil, assigns(:category) | |
153 | + assert_equal nil, @controller.send(:parent) | |
154 | + end | |
155 | + | |
156 | + protected | |
157 | + def mock_category(stubs={}) | |
158 | + @mock_category ||= mock(stubs) | |
159 | + end | |
160 | + | |
161 | + def mock_product(stubs={}) | |
162 | + @mock_product ||= mock(stubs) | |
163 | + end | |
164 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/polymorphic_test.rb
0 → 100644
... | ... | @@ -0,0 +1,186 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Factory; end | |
4 | +class Company; end | |
5 | + | |
6 | +class Employee | |
7 | + def self.human_name; 'Employee'; end | |
8 | +end | |
9 | + | |
10 | +class EmployeesController < InheritedResources::Base | |
11 | + belongs_to :factory, :company, :polymorphic => true | |
12 | +end | |
13 | + | |
14 | +class PolymorphicFactoriesTest < ActionController::TestCase | |
15 | + tests EmployeesController | |
16 | + | |
17 | + def setup | |
18 | + Factory.expects(:find).with('37').returns(mock_factory) | |
19 | + mock_factory.expects(:employees).returns(Employee) | |
20 | + | |
21 | + @controller.stubs(:resource_url).returns('/') | |
22 | + @controller.stubs(:collection_url).returns('/') | |
23 | + end | |
24 | + | |
25 | + def test_expose_all_employees_as_instance_variable_on_index | |
26 | + Employee.expects(:find).with(:all).returns([mock_employee]) | |
27 | + get :index, :factory_id => '37' | |
28 | + assert_equal mock_factory, assigns(:factory) | |
29 | + assert_equal [mock_employee], assigns(:employees) | |
30 | + end | |
31 | + | |
32 | + def test_expose_the_resquested_employee_on_show | |
33 | + Employee.expects(:find).with('42').returns(mock_employee) | |
34 | + get :show, :id => '42', :factory_id => '37' | |
35 | + assert_equal mock_factory, assigns(:factory) | |
36 | + assert_equal mock_employee, assigns(:employee) | |
37 | + end | |
38 | + | |
39 | + def test_expose_a_new_employee_on_new | |
40 | + Employee.expects(:build).returns(mock_employee) | |
41 | + get :new, :factory_id => '37' | |
42 | + assert_equal mock_factory, assigns(:factory) | |
43 | + assert_equal mock_employee, assigns(:employee) | |
44 | + end | |
45 | + | |
46 | + def test_expose_the_resquested_employee_on_edit | |
47 | + Employee.expects(:find).with('42').returns(mock_employee) | |
48 | + get :edit, :id => '42', :factory_id => '37' | |
49 | + assert_equal mock_factory, assigns(:factory) | |
50 | + assert_equal mock_employee, assigns(:employee) | |
51 | + assert_response :success | |
52 | + end | |
53 | + | |
54 | + def test_expose_a_newly_create_employee_on_create | |
55 | + Employee.expects(:build).with({'these' => 'params'}).returns(mock_employee(:save => true)) | |
56 | + post :create, :factory_id => '37', :employee => {:these => 'params'} | |
57 | + assert_equal mock_factory, assigns(:factory) | |
58 | + assert_equal mock_employee, assigns(:employee) | |
59 | + end | |
60 | + | |
61 | + def test_update_the_requested_object_on_update | |
62 | + Employee.expects(:find).with('42').returns(mock_employee) | |
63 | + mock_employee.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
64 | + put :update, :id => '42', :factory_id => '37', :employee => {:these => 'params'} | |
65 | + assert_equal mock_factory, assigns(:factory) | |
66 | + assert_equal mock_employee, assigns(:employee) | |
67 | + end | |
68 | + | |
69 | + def test_the_resquested_employee_is_destroyed_on_destroy | |
70 | + Employee.expects(:find).with('42').returns(mock_employee) | |
71 | + mock_employee.expects(:destroy) | |
72 | + delete :destroy, :id => '42', :factory_id => '37' | |
73 | + assert_equal mock_factory, assigns(:factory) | |
74 | + assert_equal mock_employee, assigns(:employee) | |
75 | + end | |
76 | + | |
77 | + def test_polymorphic_helpers | |
78 | + mock_factory.stubs(:class).returns(Factory) | |
79 | + | |
80 | + Employee.expects(:find).with(:all).returns([mock_employee]) | |
81 | + get :index, :factory_id => '37' | |
82 | + | |
83 | + assert @controller.send(:parent?) | |
84 | + assert_equal :factory, assigns(:parent_type) | |
85 | + assert_equal :factory, @controller.send(:parent_type) | |
86 | + assert_equal Factory, @controller.send(:parent_class) | |
87 | + assert_equal mock_factory, assigns(:factory) | |
88 | + assert_equal mock_factory, @controller.send(:parent) | |
89 | + end | |
90 | + | |
91 | + protected | |
92 | + def mock_factory(stubs={}) | |
93 | + @mock_factory ||= mock(stubs) | |
94 | + end | |
95 | + | |
96 | + def mock_employee(stubs={}) | |
97 | + @mock_employee ||= mock(stubs) | |
98 | + end | |
99 | +end | |
100 | + | |
101 | +class PolymorphicCompanyTest < ActionController::TestCase | |
102 | + tests EmployeesController | |
103 | + | |
104 | + def setup | |
105 | + Company.expects(:find).with('37').returns(mock_company) | |
106 | + mock_company.expects(:employees).returns(Employee) | |
107 | + | |
108 | + @controller.stubs(:resource_url).returns('/') | |
109 | + @controller.stubs(:collection_url).returns('/') | |
110 | + end | |
111 | + | |
112 | + def test_expose_all_employees_as_instance_variable_on_index | |
113 | + Employee.expects(:find).with(:all).returns([mock_employee]) | |
114 | + get :index, :company_id => '37' | |
115 | + assert_equal mock_company, assigns(:company) | |
116 | + assert_equal [mock_employee], assigns(:employees) | |
117 | + end | |
118 | + | |
119 | + def test_expose_the_resquested_employee_on_show | |
120 | + Employee.expects(:find).with('42').returns(mock_employee) | |
121 | + get :show, :id => '42', :company_id => '37' | |
122 | + assert_equal mock_company, assigns(:company) | |
123 | + assert_equal mock_employee, assigns(:employee) | |
124 | + end | |
125 | + | |
126 | + def test_expose_a_new_employee_on_new | |
127 | + Employee.expects(:build).returns(mock_employee) | |
128 | + get :new, :company_id => '37' | |
129 | + assert_equal mock_company, assigns(:company) | |
130 | + assert_equal mock_employee, assigns(:employee) | |
131 | + end | |
132 | + | |
133 | + def test_expose_the_resquested_employee_on_edit | |
134 | + Employee.expects(:find).with('42').returns(mock_employee) | |
135 | + get :edit, :id => '42', :company_id => '37' | |
136 | + assert_equal mock_company, assigns(:company) | |
137 | + assert_equal mock_employee, assigns(:employee) | |
138 | + assert_response :success | |
139 | + end | |
140 | + | |
141 | + def test_expose_a_newly_create_employee_on_create | |
142 | + Employee.expects(:build).with({'these' => 'params'}).returns(mock_employee(:save => true)) | |
143 | + post :create, :company_id => '37', :employee => {:these => 'params'} | |
144 | + assert_equal mock_company, assigns(:company) | |
145 | + assert_equal mock_employee, assigns(:employee) | |
146 | + end | |
147 | + | |
148 | + def test_update_the_requested_object_on_update | |
149 | + Employee.expects(:find).with('42').returns(mock_employee) | |
150 | + mock_employee.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
151 | + put :update, :id => '42', :company_id => '37', :employee => {:these => 'params'} | |
152 | + assert_equal mock_company, assigns(:company) | |
153 | + assert_equal mock_employee, assigns(:employee) | |
154 | + end | |
155 | + | |
156 | + def test_the_resquested_employee_is_destroyed_on_destroy | |
157 | + Employee.expects(:find).with('42').returns(mock_employee) | |
158 | + mock_employee.expects(:destroy) | |
159 | + delete :destroy, :id => '42', :company_id => '37' | |
160 | + assert_equal mock_company, assigns(:company) | |
161 | + assert_equal mock_employee, assigns(:employee) | |
162 | + end | |
163 | + | |
164 | + def test_polymorphic_helpers | |
165 | + mock_company.stubs(:class).returns(Company) | |
166 | + | |
167 | + Employee.expects(:find).with(:all).returns([mock_employee]) | |
168 | + get :index, :company_id => '37' | |
169 | + | |
170 | + assert @controller.send(:parent?) | |
171 | + assert_equal :company, assigns(:parent_type) | |
172 | + assert_equal :company, @controller.send(:parent_type) | |
173 | + assert_equal Company, @controller.send(:parent_class) | |
174 | + assert_equal mock_company, assigns(:company) | |
175 | + assert_equal mock_company, @controller.send(:parent) | |
176 | + end | |
177 | + | |
178 | + protected | |
179 | + def mock_company(stubs={}) | |
180 | + @mock_company ||= mock(stubs) | |
181 | + end | |
182 | + | |
183 | + def mock_employee(stubs={}) | |
184 | + @mock_employee ||= mock(stubs) | |
185 | + end | |
186 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/redirect_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,77 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Machine; | |
4 | + def self.human_name; 'Machine'; end | |
5 | +end | |
6 | + | |
7 | +class MachinesController < InheritedResources::Base | |
8 | + def create | |
9 | + create!{ complex_url(:create, true, true) } | |
10 | + end | |
11 | + | |
12 | + def update | |
13 | + update!{ complex_url(:update, false, false) } | |
14 | + end | |
15 | + | |
16 | + def destroy | |
17 | + destroy!{ complex_url(:destroy, true, false) } | |
18 | + end | |
19 | + | |
20 | + protected | |
21 | + def complex_url(name, arg2, arg3) | |
22 | + 'http://test.host/' + name.to_s | |
23 | + end | |
24 | +end | |
25 | + | |
26 | +class RedirectToWithBlockTest < ActionController::TestCase | |
27 | + tests MachinesController | |
28 | + | |
29 | + def test_redirect_to_the_given_url_on_create | |
30 | + Machine.stubs(:new).returns(mock_machine(:save => true)) | |
31 | + @controller.expects(:resource_url).times(0) | |
32 | + post :create | |
33 | + assert_redirected_to 'http://test.host/create' | |
34 | + end | |
35 | + | |
36 | + def test_redirect_to_the_given_url_on_update | |
37 | + Machine.stubs(:find).returns(mock_machine(:update_attributes => true)) | |
38 | + @controller.expects(:resource_url).times(0) | |
39 | + put :update | |
40 | + assert_redirected_to 'http://test.host/update' | |
41 | + end | |
42 | + | |
43 | + def test_redirect_to_the_given_url_on_destroy | |
44 | + Machine.stubs(:find).returns(mock_machine(:destroy => true)) | |
45 | + @controller.expects(:collection_url).times(0) | |
46 | + delete :destroy | |
47 | + assert_redirected_to 'http://test.host/destroy' | |
48 | + end | |
49 | + | |
50 | + protected | |
51 | + def mock_machine(stubs={}) | |
52 | + @mock_machine ||= mock(stubs) | |
53 | + end | |
54 | +end | |
55 | + | |
56 | + | |
57 | +# Use this to test blocks with multiple arity in the future. | |
58 | +class SuperMachinesController < InheritedResources::Base | |
59 | + defaults :resource_class => Machine | |
60 | + | |
61 | + def create | |
62 | + create! do |arg1, arg2, arg3| | |
63 | + # nothing | |
64 | + end | |
65 | + end | |
66 | +end | |
67 | + | |
68 | +class RedirectToArityTest < ActionController::TestCase | |
69 | + tests SuperMachinesController | |
70 | + | |
71 | + def test_redirect_to_the_given_url_on_create | |
72 | + Machine.stubs(:new).returns(:anything) | |
73 | + assert_raise ScriptError, /arity/ do | |
74 | + post :create | |
75 | + end | |
76 | + end | |
77 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/respond_to_test.rb
0 → 100644
... | ... | @@ -0,0 +1,314 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Project | |
4 | + def to_html | |
5 | + 'Generated HTML' | |
6 | + end | |
7 | + | |
8 | + def to_xml | |
9 | + 'Generated XML' | |
10 | + end | |
11 | + | |
12 | + [:to_json, :to_rss, :to_rjs].each do |method| | |
13 | + undef_method method if respond_to? method | |
14 | + end | |
15 | +end | |
16 | + | |
17 | +class ProjectsController < ActionController::Base | |
18 | + # Inherited respond_to definition is: | |
19 | + # respond_to :html | |
20 | + respond_to :html | |
21 | + respond_to :xml, :except => :edit | |
22 | + respond_to :rjs => :edit | |
23 | + respond_to :rss, :only => 'index' | |
24 | + respond_to :json, :except => :index | |
25 | + respond_to :csv, :except => :index | |
26 | + | |
27 | + def index | |
28 | + respond_with(Project.new) | |
29 | + end | |
30 | + | |
31 | + def respond_with_options | |
32 | + respond_with(Project.new, :to => [:xml, :json], :location => 'http://test.host/') | |
33 | + end | |
34 | + | |
35 | + def skip_not_acceptable | |
36 | + respond_with(Project.new, :skip_not_acceptable => true) | |
37 | + render :text => 'Will not raise double render error.' | |
38 | + end | |
39 | + | |
40 | + def respond_to_with_resource | |
41 | + respond_to(:with => Project.new) | |
42 | + end | |
43 | + | |
44 | + def respond_to_with_resource_and_blocks | |
45 | + respond_to(:with => Project.new) do |format| | |
46 | + format.json { render :text => 'Render JSON' } | |
47 | + format.rss { render :text => 'Render RSS' } | |
48 | + end | |
49 | + end | |
50 | + | |
51 | + # If the user request Mime::ALL and we have a template called action.html.erb, | |
52 | + # the html template should be rendered *unless* html is specified inside the | |
53 | + # block. This tests exactly this case. | |
54 | + # | |
55 | + def respond_to_skip_default_template | |
56 | + respond_to(:with => Project.new) do |format| | |
57 | + format.html { render :text => 'Render HTML' } | |
58 | + end | |
59 | + end | |
60 | +end | |
61 | + | |
62 | +class SuperProjectsController < ProjectsController | |
63 | +end | |
64 | + | |
65 | +class RespondToUnitTest < ActionController::TestCase | |
66 | + tests ProjectsController | |
67 | + | |
68 | + def setup | |
69 | + @formats = @controller.formats_for_respond_to | |
70 | + @responder = ActionController::MimeResponds::Responder.new(@controller) | |
71 | + end | |
72 | + | |
73 | + def test_respond_to_class_method_without_options | |
74 | + assert_nil @formats[:html][:only] | |
75 | + assert_nil @formats[:html][:except] | |
76 | + end | |
77 | + | |
78 | + def test_respond_to_class_method_inheritance | |
79 | + assert_nil @formats[:xml][:only] | |
80 | + assert_equal [:edit], @formats[:xml][:except] | |
81 | + end | |
82 | + | |
83 | + def test_respond_to_class_method_with_implicit_only | |
84 | + assert_equal [:edit], @formats[:rjs][:only] | |
85 | + assert_nil @formats[:rjs][:except] | |
86 | + end | |
87 | + | |
88 | + def test_respond_to_class_method_with_explicit_only | |
89 | + assert_equal [:index], @formats[:rss][:only] | |
90 | + assert_nil @formats[:rss][:except] | |
91 | + end | |
92 | + | |
93 | + def test_respond_to_class_method_with_explicit_except | |
94 | + assert_nil @formats[:json][:only] | |
95 | + assert_equal [:index], @formats[:json][:except] | |
96 | + end | |
97 | + | |
98 | + def test_action_respond_to_format | |
99 | + @controller.action_name = 'index' | |
100 | + assert @responder.action_respond_to_format?('html') # defined | |
101 | + assert @responder.action_respond_to_format?('xml') # inherited | |
102 | + assert @responder.action_respond_to_format?('rss') # explicit only | |
103 | + assert !@responder.action_respond_to_format?('json') # exception | |
104 | + | |
105 | + @controller.action_name = 'edit' | |
106 | + assert !@responder.action_respond_to_format?('xml') # inherited | |
107 | + assert @responder.action_respond_to_format?('rjs') # implicit only | |
108 | + assert @responder.action_respond_to_format?('json') # exception | |
109 | + end | |
110 | + | |
111 | + def test_action_respond_to_format_with_additional_mimes | |
112 | + assert @responder.action_respond_to_format?('html', [:xml, :html, :json]) | |
113 | + assert !@responder.action_respond_to_format?('html', [:xml, :rss, :json]) | |
114 | + | |
115 | + @controller.action_name = 'index' | |
116 | + assert @responder.action_respond_to_format?('html', []) | |
117 | + assert !@responder.action_respond_to_format?('json', []) | |
118 | + end | |
119 | + | |
120 | + def test_clear_respond_to | |
121 | + @controller = SuperProjectsController.new | |
122 | + @controller.request = ActionController::TestRequest.new | |
123 | + | |
124 | + @controller.action_name = 'index' | |
125 | + @responder = ActionController::MimeResponds::Responder.new(@controller) | |
126 | + | |
127 | + # Those responses are inherited from ProjectsController | |
128 | + assert @responder.action_respond_to_format?('html') # defined | |
129 | + assert @responder.action_respond_to_format?('xml') # inherited | |
130 | + assert @responder.action_respond_to_format?('rss') # explicit only | |
131 | + | |
132 | + # Let's clear respond_to definitions | |
133 | + SuperProjectsController.send(:clear_respond_to!) | |
134 | + | |
135 | + assert !@responder.action_respond_to_format?('html') | |
136 | + assert !@responder.action_respond_to_format?('xml') | |
137 | + assert !@responder.action_respond_to_format?('rss') | |
138 | + end | |
139 | + | |
140 | + def test_respond_except_any_does_not_respond_to_mime_all | |
141 | + prepare_responder_to_respond! | |
142 | + | |
143 | + @responder.respond_except_any | |
144 | + assert !@performed | |
145 | + | |
146 | + @responder.respond | |
147 | + assert @performed | |
148 | + end | |
149 | + | |
150 | + def test_respond_any_responds_to_mime_all | |
151 | + prepare_responder_to_respond! | |
152 | + | |
153 | + @responder.respond_any | |
154 | + assert @performed | |
155 | + end | |
156 | + | |
157 | + def test_respond_any_responds_only_to_all | |
158 | + prepare_responder_to_respond!('text/html') | |
159 | + | |
160 | + @responder.respond_any | |
161 | + assert !@performed | |
162 | + end | |
163 | + | |
164 | + def test_responder_prioritize | |
165 | + prepare_responder_to_respond! | |
166 | + assert_equal [Mime::HTML, Mime::XML], @responder.order | |
167 | + | |
168 | + @responder.prioritize(:xml) | |
169 | + assert_equal [Mime::XML, Mime::HTML], @responder.order | |
170 | + | |
171 | + @responder.prioritize(:js) | |
172 | + assert_equal [Mime::XML, Mime::HTML], @responder.order | |
173 | + end | |
174 | + | |
175 | + protected | |
176 | + def prepare_responder_to_respond!(content_type='*/*') | |
177 | + @controller.request = @request = ActionController::TestRequest.new | |
178 | + @controller.response = @response = ActionController::TestResponse.new | |
179 | + | |
180 | + @request.accept = content_type | |
181 | + @responder = ActionController::MimeResponds::Responder.new(@controller) | |
182 | + @performed = false | |
183 | + | |
184 | + # Mock template | |
185 | + template = mock() | |
186 | + @response.stubs(:template).returns(template) | |
187 | + template.stubs(:template_format=).returns(true) | |
188 | + | |
189 | + respond_to_declaration = proc { |format| | |
190 | + format.html { @performed = true } | |
191 | + format.xml { } | |
192 | + } | |
193 | + | |
194 | + respond_to_declaration.call(@responder) | |
195 | + end | |
196 | +end | |
197 | + | |
198 | +class RespondToFunctionalTest < ActionController::TestCase | |
199 | + tests ProjectsController | |
200 | + | |
201 | + def test_respond_with_layout_rendering | |
202 | + @request.accept = 'text/html' | |
203 | + get :index | |
204 | + assert_equal 'Index HTML', @response.body.strip | |
205 | + end | |
206 | + | |
207 | + def test_respond_with_calls_to_format_on_resource | |
208 | + @request.accept = 'application/xml' | |
209 | + get :index | |
210 | + assert_equal 'Generated XML', @response.body.strip | |
211 | + end | |
212 | + | |
213 | + def test_respond_with_inherits_format | |
214 | + @request.accept = 'application/xml' | |
215 | + get :index | |
216 | + assert_equal 'Generated XML', @response.body.strip | |
217 | + end | |
218 | + | |
219 | + def test_respond_with_renders_status_not_acceptable_if_mime_type_is_not_registered | |
220 | + @request.accept = 'text/csv' | |
221 | + get :index | |
222 | + assert_equal '406 Not Acceptable', @response.status | |
223 | + end | |
224 | + | |
225 | + def test_respond_with_renders_not_found_when_mime_type_is_valid_but_could_not_render | |
226 | + @request.accept = 'application/rss+xml' | |
227 | + get :index | |
228 | + assert_equal '404 Not Found', @response.status | |
229 | + end | |
230 | + | |
231 | + def test_respond_to_all | |
232 | + @request.accept = '*/*' | |
233 | + get :index | |
234 | + assert_equal 'Index HTML', @response.body.strip | |
235 | + end | |
236 | + | |
237 | + def test_default_template_is_not_rendered_if_template_format_is_not_accepted | |
238 | + @controller.stubs(:default_template_format).returns(:json) | |
239 | + @request.accept = '*/*' | |
240 | + get :index | |
241 | + assert_equal '406 Not Acceptable', @response.status | |
242 | + end | |
243 | + | |
244 | + def test_respond_with_sets_content_type_properly | |
245 | + @request.accept = 'text/html' | |
246 | + get :index | |
247 | + assert_equal 'text/html', @response.content_type | |
248 | + assert_equal :html, @response.template.template_format | |
249 | + | |
250 | + @request.accept = 'application/xml' | |
251 | + get :index | |
252 | + assert_equal 'application/xml', @response.content_type | |
253 | + assert_equal :xml, @response.template.template_format | |
254 | + end | |
255 | + | |
256 | + def test_respond_with_when_to_is_given_as_option | |
257 | + @request.accept = 'text/html' | |
258 | + get :respond_with_options | |
259 | + assert_equal '406 Not Acceptable', @response.status | |
260 | + | |
261 | + @request.accept = 'application/xml' | |
262 | + get :respond_with_options | |
263 | + assert_equal 'Generated XML', @response.body.strip | |
264 | + end | |
265 | + | |
266 | + def test_respond_with_forwads_extra_options_to_render | |
267 | + @request.accept = 'application/xml' | |
268 | + get :respond_with_options | |
269 | + assert_equal 'Generated XML', @response.body.strip | |
270 | + assert_equal 'http://test.host/', @response.headers['Location'] | |
271 | + end | |
272 | + | |
273 | + def test_respond_with_skips_head_when_skip_not_acceptable_is_given | |
274 | + @request.accept = 'application/rss+xml' | |
275 | + get :skip_not_acceptable | |
276 | + assert_equal 'Will not raise double render error.', @response.body.strip | |
277 | + end | |
278 | + | |
279 | + def test_respond_to_when_a_resource_is_given_as_option | |
280 | + @request.accept = 'text/html' | |
281 | + get :respond_to_with_resource | |
282 | + assert_equal 'RespondTo HTML', @response.body.strip | |
283 | + | |
284 | + @request.accept = 'application/xml' | |
285 | + get :respond_to_with_resource | |
286 | + assert_equal 'Generated XML', @response.body.strip | |
287 | + | |
288 | + @request.accept = 'application/json' | |
289 | + get :respond_to_with_resource | |
290 | + assert_equal '404 Not Found', @response.status | |
291 | + | |
292 | + @request.accept = 'application/rss+xml' | |
293 | + get :respond_to_with_resource | |
294 | + assert_equal '406 Not Acceptable', @response.status | |
295 | + end | |
296 | + | |
297 | + def test_respond_to_overwrite_class_method_definition | |
298 | + @request.accept = 'application/rss+xml' | |
299 | + get :respond_to_with_resource_and_blocks | |
300 | + assert_equal 'Render RSS', @response.body.strip | |
301 | + end | |
302 | + | |
303 | + def test_respond_to_fallback_to_first_block_when_mime_type_is_all | |
304 | + @request.accept = '*/*' | |
305 | + get :respond_to_with_resource_and_blocks | |
306 | + assert_equal 'Render JSON', @response.body.strip | |
307 | + end | |
308 | + | |
309 | + def test_respond_to_skip_default_template_when_it_is_in_block | |
310 | + @request.accept = '*/*' | |
311 | + get :respond_to_skip_default_template | |
312 | + assert_equal 'Render HTML', @response.body.strip | |
313 | + end | |
314 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/singleton_test.rb
0 → 100644
... | ... | @@ -0,0 +1,83 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +# This test file is instead to test the how controller flow and actions | |
4 | +# using a belongs_to association. This is done using mocks a la rspec. | |
5 | +# | |
6 | +class Store | |
7 | +end | |
8 | + | |
9 | +class Manager | |
10 | + def self.human_name; 'Manager'; end | |
11 | +end | |
12 | + | |
13 | +class ManagersController < InheritedResources::Base | |
14 | + belongs_to :store, :singleton => true | |
15 | +end | |
16 | + | |
17 | +class SingletonTest < ActionController::TestCase | |
18 | + tests ManagersController | |
19 | + | |
20 | + def setup | |
21 | + @controller.stubs(:resource_url).returns('/') | |
22 | + @controller.stubs(:collection_url).returns('/') | |
23 | + end | |
24 | + | |
25 | + def test_expose_the_resquested_manager_on_show | |
26 | + Store.expects(:find).with('37').returns(mock_store) | |
27 | + mock_store.expects(:manager).returns(mock_manager) | |
28 | + get :show, :store_id => '37' | |
29 | + assert_equal mock_store, assigns(:store) | |
30 | + assert_equal mock_manager, assigns(:manager) | |
31 | + end | |
32 | + | |
33 | + def test_expose_a_new_manager_on_new | |
34 | + Store.expects(:find).with('37').returns(mock_store) | |
35 | + mock_store.expects(:build_manager).returns(mock_manager) | |
36 | + get :new, :store_id => '37' | |
37 | + assert_equal mock_store, assigns(:store) | |
38 | + assert_equal mock_manager, assigns(:manager) | |
39 | + end | |
40 | + | |
41 | + def test_expose_the_resquested_manager_on_edit | |
42 | + Store.expects(:find).with('37').returns(mock_store) | |
43 | + mock_store.expects(:manager).returns(mock_manager) | |
44 | + get :edit, :store_id => '37' | |
45 | + assert_equal mock_store, assigns(:store) | |
46 | + assert_equal mock_manager, assigns(:manager) | |
47 | + assert_response :success | |
48 | + end | |
49 | + | |
50 | + def test_expose_a_newly_create_manager_on_create | |
51 | + Store.expects(:find).with('37').returns(mock_store) | |
52 | + mock_store.expects(:build_manager).with({'these' => 'params'}).returns(mock_manager(:save => true)) | |
53 | + post :create, :store_id => '37', :manager => {:these => 'params'} | |
54 | + assert_equal mock_store, assigns(:store) | |
55 | + assert_equal mock_manager, assigns(:manager) | |
56 | + end | |
57 | + | |
58 | + def test_update_the_requested_object_on_update | |
59 | + Store.expects(:find).with('37').returns(mock_store(:manager => mock_manager)) | |
60 | + mock_manager.expects(:update_attributes).with({'these' => 'params'}).returns(true) | |
61 | + put :update, :store_id => '37', :manager => {:these => 'params'} | |
62 | + assert_equal mock_store, assigns(:store) | |
63 | + assert_equal mock_manager, assigns(:manager) | |
64 | + end | |
65 | + | |
66 | + def test_the_resquested_manager_is_destroyed_on_destroy | |
67 | + Store.expects(:find).with('37').returns(mock_store) | |
68 | + mock_store.expects(:manager).returns(mock_manager) | |
69 | + mock_manager.expects(:destroy) | |
70 | + delete :destroy, :store_id => '37' | |
71 | + assert_equal mock_store, assigns(:store) | |
72 | + assert_equal mock_manager, assigns(:manager) | |
73 | + end | |
74 | + | |
75 | + protected | |
76 | + def mock_store(stubs={}) | |
77 | + @mock_store ||= mock(stubs) | |
78 | + end | |
79 | + | |
80 | + def mock_manager(stubs={}) | |
81 | + @mock_manager ||= mock(stubs) | |
82 | + end | |
83 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/test_helper.rb
0 → 100644
... | ... | @@ -0,0 +1,27 @@ |
1 | +require 'test/unit' | |
2 | +require 'rubygems' | |
3 | +require 'ruby-debug' | |
4 | +require 'mocha' | |
5 | + | |
6 | +ENV["RAILS_ENV"] = "test" | |
7 | +RAILS_ROOT = "anywhere" | |
8 | + | |
9 | +require 'active_support' | |
10 | +require 'action_controller' | |
11 | +require 'action_controller/test_case' | |
12 | +require 'action_controller/test_process' | |
13 | + | |
14 | +I18n.load_path << File.join(File.dirname(__FILE__), 'locales', 'en.yml') | |
15 | +I18n.reload! | |
16 | + | |
17 | +class ApplicationController < ActionController::Base; end | |
18 | + | |
19 | +# Add IR to load path and load the main file | |
20 | +ActiveSupport::Dependencies.load_paths << File.expand_path(File.dirname(__FILE__) + '/../lib') | |
21 | +require_dependency 'inherited_resources' | |
22 | + | |
23 | +ActionController::Base.view_paths = File.join(File.dirname(__FILE__), 'views') | |
24 | + | |
25 | +ActionController::Routing::Routes.draw do |map| | |
26 | + map.connect ':controller/:action/:id' | |
27 | +end | ... | ... |
vendor/gems/josevalim-inherited_resources-0.8.5/test/url_helpers_test.rb
0 → 100644
... | ... | @@ -0,0 +1,471 @@ |
1 | +require File.dirname(__FILE__) + '/test_helper' | |
2 | + | |
3 | +class Universe; end | |
4 | +class UniversesController < InheritedResources::Base | |
5 | + defaults :singleton => true, :route_instance_name => 'universum' | |
6 | +end | |
7 | + | |
8 | +class House; end | |
9 | +class HousesController < InheritedResources::Base | |
10 | +end | |
11 | + | |
12 | +class Backpack; end | |
13 | +module Admin; end | |
14 | +class Admin::BackpacksController < InheritedResources::Base | |
15 | + defaults :route_collection_name => 'tour_backpacks' | |
16 | +end | |
17 | + | |
18 | +class Table; end | |
19 | +class TablesController < InheritedResources::Base | |
20 | + belongs_to :house | |
21 | +end | |
22 | + | |
23 | +class RoomsController < InheritedResources::Base | |
24 | + belongs_to :house, :route_name => 'big_house' | |
25 | +end | |
26 | + | |
27 | +class ChairsController < InheritedResources::Base | |
28 | + belongs_to :house do | |
29 | + belongs_to :table | |
30 | + end | |
31 | +end | |
32 | + | |
33 | +class OwnersController < InheritedResources::Base | |
34 | + singleton_belongs_to :house | |
35 | +end | |
36 | + | |
37 | +class Bed; end | |
38 | +class BedsController < InheritedResources::Base | |
39 | + optional_belongs_to :house, :building | |
40 | +end | |
41 | + | |
42 | +class Desk; end | |
43 | +module Admin | |
44 | + class DesksController < InheritedResources::Base | |
45 | + optional_belongs_to :house | |
46 | + end | |
47 | +end | |
48 | + | |
49 | +class Dish; end | |
50 | +class DishesController < InheritedResources::Base | |
51 | + belongs_to :house do | |
52 | + polymorphic_belongs_to :table, :kitchen | |
53 | + end | |
54 | +end | |
55 | + | |
56 | +class Center; end | |
57 | +class CentersController < InheritedResources::Base | |
58 | + acts_as_singleton! | |
59 | + | |
60 | + belongs_to :house do | |
61 | + belongs_to :table, :kitchen, :polymorphic => true | |
62 | + end | |
63 | +end | |
64 | + | |
65 | +# Create a TestHelper module with some helpers | |
66 | +class UrlHelpersTest < ActiveSupport::TestCase | |
67 | + | |
68 | + def test_url_helpers_on_simple_inherited_resource | |
69 | + controller = HousesController.new | |
70 | + controller.instance_variable_set('@house', :house) | |
71 | + | |
72 | + [:url, :path].each do |path_or_url| | |
73 | + controller.expects("houses_#{path_or_url}").with({}).once | |
74 | + controller.send("collection_#{path_or_url}") | |
75 | + | |
76 | + controller.expects("house_#{path_or_url}").with(:house, {}).once | |
77 | + controller.send("resource_#{path_or_url}") | |
78 | + | |
79 | + controller.expects("new_house_#{path_or_url}").with({}).once | |
80 | + controller.send("new_resource_#{path_or_url}") | |
81 | + | |
82 | + controller.expects("edit_house_#{path_or_url}").with(:house, {}).once | |
83 | + controller.send("edit_resource_#{path_or_url}") | |
84 | + | |
85 | + # With arg | |
86 | + controller.expects("house_#{path_or_url}").with(:arg, {}).once | |
87 | + controller.send("resource_#{path_or_url}", :arg) | |
88 | + | |
89 | + controller.expects("house_#{path_or_url}").with(:arg, {}).once | |
90 | + controller.send("resource_#{path_or_url}", :arg) | |
91 | + | |
92 | + # With options | |
93 | + controller.expects("house_#{path_or_url}").with(:arg, :page => 1).once | |
94 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
95 | + end | |
96 | + end | |
97 | + | |
98 | + def test_url_helpers_on_simple_inherited_namespaced_resource | |
99 | + controller = Admin::BackpacksController.new | |
100 | + controller.instance_variable_set('@backpack', :backpack) | |
101 | + | |
102 | + assert_equal 'admin', controller.class.resources_configuration[:self][:route_prefix] | |
103 | + | |
104 | + [:url, :path].each do |path_or_url| | |
105 | + controller.expects("admin_tour_backpacks_#{path_or_url}").with({}).once | |
106 | + controller.send("collection_#{path_or_url}") | |
107 | + | |
108 | + controller.expects("admin_backpack_#{path_or_url}").with(:backpack, {}).once | |
109 | + controller.send("resource_#{path_or_url}") | |
110 | + | |
111 | + controller.expects("new_admin_backpack_#{path_or_url}").with({}).once | |
112 | + controller.send("new_resource_#{path_or_url}") | |
113 | + | |
114 | + controller.expects("edit_admin_backpack_#{path_or_url}").with(:backpack, {}).once | |
115 | + controller.send("edit_resource_#{path_or_url}") | |
116 | + | |
117 | + # With arg | |
118 | + controller.expects("admin_backpack_#{path_or_url}").with(:arg, {}).once | |
119 | + controller.send("resource_#{path_or_url}", :arg) | |
120 | + | |
121 | + controller.expects("admin_backpack_#{path_or_url}").with(:arg, {}).once | |
122 | + controller.send("resource_#{path_or_url}", :arg) | |
123 | + | |
124 | + # With options | |
125 | + controller.expects("admin_backpack_#{path_or_url}").with(:arg, :page => 1).once | |
126 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
127 | + end | |
128 | + end | |
129 | + | |
130 | + def test_url_helpers_on_simple_inherited_singleton_resource | |
131 | + controller = UniversesController.new | |
132 | + controller.instance_variable_set('@universe', :universe) | |
133 | + | |
134 | + [:url, :path].each do |path_or_url| | |
135 | + controller.expects("root_#{path_or_url}").with({}).once | |
136 | + controller.send("collection_#{path_or_url}") | |
137 | + | |
138 | + controller.expects("universum_#{path_or_url}").with({}).once | |
139 | + controller.send("resource_#{path_or_url}") | |
140 | + | |
141 | + controller.expects("new_universum_#{path_or_url}").with({}).once | |
142 | + controller.send("new_resource_#{path_or_url}") | |
143 | + | |
144 | + controller.expects("edit_universum_#{path_or_url}").with({}).once | |
145 | + controller.send("edit_resource_#{path_or_url}") | |
146 | + | |
147 | + # With options | |
148 | + # Also tests that argument sent are not used | |
149 | + controller.expects("universum_#{path_or_url}").with(:page => 1).once | |
150 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
151 | + end | |
152 | + end | |
153 | + | |
154 | + def test_url_helpers_on_belongs_to | |
155 | + controller = TablesController.new | |
156 | + controller.instance_variable_set('@house', :house) | |
157 | + controller.instance_variable_set('@table', :table) | |
158 | + | |
159 | + [:url, :path].each do |path_or_url| | |
160 | + controller.expects("house_tables_#{path_or_url}").with(:house, {}).once | |
161 | + controller.send("collection_#{path_or_url}") | |
162 | + | |
163 | + controller.expects("house_table_#{path_or_url}").with(:house, :table, {}).once | |
164 | + controller.send("resource_#{path_or_url}") | |
165 | + | |
166 | + controller.expects("new_house_table_#{path_or_url}").with(:house, {}).once | |
167 | + controller.send("new_resource_#{path_or_url}") | |
168 | + | |
169 | + controller.expects("edit_house_table_#{path_or_url}").with(:house, :table, {}).once | |
170 | + controller.send("edit_resource_#{path_or_url}") | |
171 | + | |
172 | + # With arg | |
173 | + controller.expects("house_table_#{path_or_url}").with(:house, :arg, {}).once | |
174 | + controller.send("resource_#{path_or_url}", :arg) | |
175 | + | |
176 | + controller.expects("edit_house_table_#{path_or_url}").with(:house, :arg, {}).once | |
177 | + controller.send("edit_resource_#{path_or_url}", :arg) | |
178 | + | |
179 | + # With options | |
180 | + controller.expects("house_table_#{path_or_url}").with(:house, :arg, :page => 1).once | |
181 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
182 | + end | |
183 | + end | |
184 | + | |
185 | + def test_url_helpers_on_not_default_belongs_to | |
186 | + controller = RoomsController.new | |
187 | + controller.instance_variable_set('@house', :house) | |
188 | + controller.instance_variable_set('@room', :room) | |
189 | + | |
190 | + [:url, :path].each do |path_or_url| | |
191 | + controller.expects("big_house_rooms_#{path_or_url}").with(:house, {}).once | |
192 | + controller.send("collection_#{path_or_url}") | |
193 | + | |
194 | + controller.expects("big_house_room_#{path_or_url}").with(:house, :room, {}).once | |
195 | + controller.send("resource_#{path_or_url}") | |
196 | + | |
197 | + controller.expects("new_big_house_room_#{path_or_url}").with(:house, {}).once | |
198 | + controller.send("new_resource_#{path_or_url}") | |
199 | + | |
200 | + controller.expects("edit_big_house_room_#{path_or_url}").with(:house, :room, {}).once | |
201 | + controller.send("edit_resource_#{path_or_url}") | |
202 | + | |
203 | + # With args | |
204 | + controller.expects("big_house_room_#{path_or_url}").with(:house, :arg, {}).once | |
205 | + controller.send("resource_#{path_or_url}", :arg) | |
206 | + | |
207 | + controller.expects("edit_big_house_room_#{path_or_url}").with(:house, :arg, {}).once | |
208 | + controller.send("edit_resource_#{path_or_url}", :arg) | |
209 | + | |
210 | + # With options | |
211 | + controller.expects("big_house_room_#{path_or_url}").with(:house, :arg, :page => 1).once | |
212 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
213 | + end | |
214 | + end | |
215 | + | |
216 | + def test_url_helpers_on_nested_belongs_to | |
217 | + controller = ChairsController.new | |
218 | + controller.instance_variable_set('@house', :house) | |
219 | + controller.instance_variable_set('@table', :table) | |
220 | + controller.instance_variable_set('@chair', :chair) | |
221 | + | |
222 | + [:url, :path].each do |path_or_url| | |
223 | + controller.expects("house_table_chairs_#{path_or_url}").with(:house, :table, {}).once | |
224 | + controller.send("collection_#{path_or_url}") | |
225 | + | |
226 | + controller.expects("house_table_chair_#{path_or_url}").with(:house, :table, :chair, {}).once | |
227 | + controller.send("resource_#{path_or_url}") | |
228 | + | |
229 | + controller.expects("new_house_table_chair_#{path_or_url}").with(:house, :table, {}).once | |
230 | + controller.send("new_resource_#{path_or_url}") | |
231 | + | |
232 | + controller.expects("edit_house_table_chair_#{path_or_url}").with(:house, :table, :chair, {}).once | |
233 | + controller.send("edit_resource_#{path_or_url}") | |
234 | + | |
235 | + # With args | |
236 | + controller.expects("edit_house_table_chair_#{path_or_url}").with(:house, :table, :arg, {}).once | |
237 | + controller.send("edit_resource_#{path_or_url}", :arg) | |
238 | + | |
239 | + controller.expects("house_table_chair_#{path_or_url}").with(:house, :table, :arg, {}).once | |
240 | + controller.send("resource_#{path_or_url}", :arg) | |
241 | + | |
242 | + # With options | |
243 | + controller.expects("edit_house_table_chair_#{path_or_url}").with(:house, :table, :arg, :page => 1).once | |
244 | + controller.send("edit_resource_#{path_or_url}", :arg, :page => 1) | |
245 | + end | |
246 | + end | |
247 | + | |
248 | + def test_url_helpers_on_singletons_with_belongs_to | |
249 | + controller = OwnersController.new | |
250 | + controller.instance_variable_set('@house', :house) | |
251 | + controller.instance_variable_set('@owner', :owner) | |
252 | + | |
253 | + [:url, :path].each do |path_or_url| | |
254 | + controller.expects("house_#{path_or_url}").with(:house, {}).once | |
255 | + controller.send("collection_#{path_or_url}") | |
256 | + | |
257 | + controller.expects("house_owner_#{path_or_url}").with(:house, {}).once | |
258 | + controller.send("resource_#{path_or_url}") | |
259 | + | |
260 | + controller.expects("new_house_owner_#{path_or_url}").with(:house, {}).once | |
261 | + controller.send("new_resource_#{path_or_url}") | |
262 | + | |
263 | + controller.expects("edit_house_owner_#{path_or_url}").with(:house, {}).once | |
264 | + controller.send("edit_resource_#{path_or_url}") | |
265 | + | |
266 | + # With options | |
267 | + # Also tests that argument sent are not used | |
268 | + controller.expects("house_owner_#{path_or_url}").with(:house, :page => 1).once | |
269 | + controller.send("resource_#{path_or_url}", :arg, :page => 1) | |
270 | + end | |
271 | + end | |
272 | + | |
273 | + def test_url_helpers_on_polymorphic_belongs_to | |
274 | + house = House.new | |
275 | + bed = Bed.new | |
276 | + | |
277 | + new_bed = Bed.new | |
278 | + Bed.stubs(:new).returns(new_bed) | |
279 | + new_bed.stubs(:new_record?).returns(true) | |
280 | + | |
281 | + controller = BedsController.new | |
282 | + controller.instance_variable_set('@parent_type', :house) | |
283 | + controller.instance_variable_set('@house', house) | |
284 | + controller.instance_variable_set('@bed', bed) | |
285 | + | |
286 | + [:url, :path].each do |path_or_url| | |
287 | + controller.expects("house_beds_#{path_or_url}").with(house).once | |
288 | + controller.send("collection_#{path_or_url}") | |
289 | + | |
290 | + controller.expects("house_bed_#{path_or_url}").with(house, bed).once | |
291 | + controller.send("resource_#{path_or_url}") | |
292 | + | |
293 | + controller.expects("new_house_bed_#{path_or_url}").with(house).once | |
294 | + controller.send("new_resource_#{path_or_url}") | |
295 | + | |
296 | + controller.expects("edit_house_bed_#{path_or_url}").with(house, bed).once | |
297 | + controller.send("edit_resource_#{path_or_url}") | |
298 | + end | |
299 | + | |
300 | + # With options | |
301 | + controller.expects("house_bed_url").with(house, bed, :page => 1).once | |
302 | + controller.send("resource_url", :page => 1) | |
303 | + | |
304 | + # With args | |
305 | + controller.expects("polymorphic_url").with([:arg, new_bed], {}).once | |
306 | + controller.send("collection_url", :arg) | |
307 | + | |
308 | + controller.expects("polymorphic_url").with([house, :arg], {}).once | |
309 | + controller.send("resource_url", :arg) | |
310 | + | |
311 | + controller.expects("edit_polymorphic_url").with([house, :arg], {}).once | |
312 | + controller.send("edit_resource_url", :arg) | |
313 | + end | |
314 | + | |
315 | + def test_url_helpers_on_namespaced_polymorphic_belongs_to | |
316 | + house = House.new | |
317 | + desk = Desk.new | |
318 | + | |
319 | + new_desk = Desk.new | |
320 | + Desk.stubs(:new).returns(new_desk) | |
321 | + new_desk.stubs(:new_record?).returns(true) | |
322 | + | |
323 | + controller = Admin::DesksController.new | |
324 | + controller.instance_variable_set('@parent_type', :house) | |
325 | + controller.instance_variable_set('@house', house) | |
326 | + controller.instance_variable_set('@desk', desk) | |
327 | + | |
328 | + [:url, :path].each do |path_or_url| | |
329 | + controller.expects("admin_house_desks_#{path_or_url}").with(house).once | |
330 | + controller.send("collection_#{path_or_url}") | |
331 | + | |
332 | + controller.expects("admin_house_desk_#{path_or_url}").with(house, desk).once | |
333 | + controller.send("resource_#{path_or_url}") | |
334 | + | |
335 | + controller.expects("new_admin_house_desk_#{path_or_url}").with(house).once | |
336 | + controller.send("new_resource_#{path_or_url}") | |
337 | + | |
338 | + controller.expects("edit_admin_house_desk_#{path_or_url}").with(house, desk).once | |
339 | + controller.send("edit_resource_#{path_or_url}") | |
340 | + end | |
341 | + | |
342 | + # With options | |
343 | + controller.expects("admin_house_desk_url").with(house, desk, :page => 1).once | |
344 | + controller.send("resource_url", :page => 1) | |
345 | + | |
346 | + # With args | |
347 | + controller.expects("polymorphic_url").with(['admin', :arg, new_desk], {}).once | |
348 | + controller.send("collection_url", :arg) | |
349 | + | |
350 | + controller.expects("polymorphic_url").with(['admin', house, :arg], {}).once | |
351 | + controller.send("resource_url", :arg) | |
352 | + | |
353 | + controller.expects("edit_polymorphic_url").with(['admin', house, :arg], {}).once | |
354 | + controller.send("edit_resource_url", :arg) | |
355 | + end | |
356 | + | |
357 | + def test_url_helpers_on_nested_polymorphic_belongs_to | |
358 | + house = House.new | |
359 | + table = Table.new | |
360 | + dish = Dish.new | |
361 | + | |
362 | + new_dish = Dish.new | |
363 | + Dish.stubs(:new).returns(new_dish) | |
364 | + new_dish.stubs(:new_record?).returns(true) | |
365 | + | |
366 | + controller = DishesController.new | |
367 | + controller.instance_variable_set('@parent_type', :table) | |
368 | + controller.instance_variable_set('@house', house) | |
369 | + controller.instance_variable_set('@table', table) | |
370 | + controller.instance_variable_set('@dish', dish) | |
371 | + | |
372 | + [:url, :path].each do |path_or_url| | |
373 | + controller.expects("house_table_dishes_#{path_or_url}").with(house, table).once | |
374 | + controller.send("collection_#{path_or_url}") | |
375 | + | |
376 | + controller.expects("house_table_dish_#{path_or_url}").with(house, table, dish).once | |
377 | + controller.send("resource_#{path_or_url}") | |
378 | + | |
379 | + controller.expects("new_house_table_dish_#{path_or_url}").with(house, table).once | |
380 | + controller.send("new_resource_#{path_or_url}") | |
381 | + | |
382 | + controller.expects("edit_house_table_dish_#{path_or_url}").with(house, table, dish).once | |
383 | + controller.send("edit_resource_#{path_or_url}") | |
384 | + end | |
385 | + | |
386 | + # With options | |
387 | + controller.expects("house_table_dish_url").with(house, table, dish, :page => 1).once | |
388 | + controller.send("resource_url", :page => 1) | |
389 | + | |
390 | + # With args | |
391 | + controller.expects("polymorphic_url").with([house, table, :arg], {}).once | |
392 | + controller.send("resource_url", :arg) | |
393 | + | |
394 | + controller.expects("edit_polymorphic_url").with([house, table, :arg], {}).once | |
395 | + controller.send("edit_resource_url", :arg) | |
396 | + end | |
397 | + | |
398 | + def test_url_helpers_on_singleton_nested_polymorphic_belongs_to | |
399 | + # This must not be usefull in singleton controllers... | |
400 | + # Center.new | |
401 | + house = House.new | |
402 | + table = Table.new | |
403 | + | |
404 | + controller = CentersController.new | |
405 | + controller.instance_variable_set('@parent_type', :table) | |
406 | + controller.instance_variable_set('@house', house) | |
407 | + controller.instance_variable_set('@table', table) | |
408 | + | |
409 | + # This must not be useful in singleton controllers... | |
410 | + # controller.instance_variable_set('@center', :center) | |
411 | + | |
412 | + [:url, :path].each do |path_or_url| | |
413 | + controller.expects("house_table_#{path_or_url}").with(house, table).once | |
414 | + controller.send("collection_#{path_or_url}") | |
415 | + | |
416 | + controller.expects("house_table_center_#{path_or_url}").with(house, table).once | |
417 | + controller.send("resource_#{path_or_url}") | |
418 | + | |
419 | + controller.expects("new_house_table_center_#{path_or_url}").with(house, table).once | |
420 | + controller.send("new_resource_#{path_or_url}") | |
421 | + | |
422 | + controller.expects("edit_house_table_center_#{path_or_url}").with(house, table).once | |
423 | + controller.send("edit_resource_#{path_or_url}") | |
424 | + end | |
425 | + | |
426 | + # With options | |
427 | + controller.expects("house_table_center_url").with(house, table, :page => 1) | |
428 | + controller.send("resource_url", :page => 1) | |
429 | + | |
430 | + # With args | |
431 | + controller.expects("polymorphic_url").with([house, table, :center], {}).once | |
432 | + controller.send("resource_url", :arg) | |
433 | + end | |
434 | + | |
435 | + def test_url_helpers_on_optional_polymorphic_belongs_to | |
436 | + bed = Bed.new | |
437 | + new_bed = Bed.new | |
438 | + Bed.stubs(:new).returns(new_bed) | |
439 | + new_bed.stubs(:new_record?).returns(true) | |
440 | + | |
441 | + controller = BedsController.new | |
442 | + controller.instance_variable_set('@parent_type', nil) | |
443 | + controller.instance_variable_set('@bed', bed) | |
444 | + | |
445 | + [:url, :path].each do |path_or_url| | |
446 | + controller.expects("beds_#{path_or_url}").with().once | |
447 | + controller.send("collection_#{path_or_url}") | |
448 | + | |
449 | + controller.expects("bed_#{path_or_url}").with(bed).once | |
450 | + controller.send("resource_#{path_or_url}") | |
451 | + | |
452 | + controller.expects("new_bed_#{path_or_url}").with().once | |
453 | + controller.send("new_resource_#{path_or_url}") | |
454 | + | |
455 | + controller.expects("edit_bed_#{path_or_url}").with(bed).once | |
456 | + controller.send("edit_resource_#{path_or_url}") | |
457 | + end | |
458 | + | |
459 | + # With options | |
460 | + controller.expects("bed_url").with(bed, :page => 1).once | |
461 | + controller.send("resource_url", :page => 1) | |
462 | + | |
463 | + # With args | |
464 | + controller.expects("polymorphic_url").with([:arg], {}).once | |
465 | + controller.send("resource_url", :arg) | |
466 | + | |
467 | + controller.expects("edit_polymorphic_url").with([:arg], {}).once | |
468 | + controller.send("edit_resource_url", :arg) | |
469 | + end | |
470 | + | |
471 | +end | ... | ... |