Refactor large routes file - ruby-on-rails

I am making various routes with a format like below:
get "address/1000broadway"
get "address/300main"
This list of routes will likely grow into the thousands. What is the best way to manage this? Can I simply list them all out in the routes file? Or is better to require various files that include the routes? Are there any potential performance issues with the application having to load a large routes.rb file?

Reading the comments,
this feels very much like a CMS type problem.
For that I'd say "treat each address as a 'page', and chuck the custom layout in the database"
But you reckon the templating is too complex to deal with this way.
Have you looked at liquid?
Namely, it'd allow you to store the template in the database, but use conditional logic.
As a bare minimum,
I'd suggest organising your urls.
resources :address do
collection do
get :1000broadway
get :300main
end
end

Related

Restful resources rails

What is the correct way to make this api 'restful'
I have a location,
GET location/:id
PUT location/:id
The spec has changed and now this location can have certain 'types' the client can update. One requirement is that the client get the allowed types (could be one of these from a fixed list - i.e.['urban', 'wilderness', 'private', etc..]) for all locations. This isn't a nested resource, its a column on the location table. I've implemented,
GET location/types_allowed
is there are better RESTFUL way?
Another example, a location can have neighbors, so I made GET locations/neighbors. I'm having trouble understanding the nuances of REST beyond CRUD and nested resources. Thanks!
Instead of a column as types_allowed, create a type resource and the relation can be like
location.rb
belongs_to :type
type.rb
has_many :locations
and with this your route file would be
resources :type do
resources :location
end
I strongly recommend against naming a model/column "type". That tends to break magic things inside of rails that you don't even know are there until you try that. It's one of those "undocumented features" :P
I'd instead recommend reading up on "single table inheritance" or "polymorphism" to figure out if either of these is right for you.
If not... then name something "kind" instead of "type" as it'll all work a lot better that way.
As to RESTful resources... you really can't go past the Rails Guides. If you follow the routing guide: (and all the other ones) you'll get an idea of how to do RESTful resources

Lots of different models in tests (rspec)? Advanced

I am only looking for answers from senior/more experienced Ruby/Rails developers on this one, since I think this is a bit more advanced of a question.
I have a gem I am working on that adds some behavior to AR models. I have to test it for a lot of different associations (has_many, habtm, has_one etc), and I also have to test behavior when different options are passed for the associations (e.g. :foreign_key). Now with all these different models, I can use the same table in the database because the fields themselves do not need to change, only behavior specified through has_many, belongs_to and so on.
Keep in mind there are a lot of different options, so the number of models is quite large.
First I don't think it would be bad practice to have the definition of the models next to / in the test itself, for readability purposes (if I have multiple tests that use the same model then I would group them together and use the before method). So this is one of my goals, and you can comment on this if you don't agree.
The second thing I am not sure of is I wanted to keep the simple/same name of the model in all the tests, for example "Task", instead of TaskWithManySubtasksAndForeignKey or something ugly like that. The problem is there are so many models it's hard to come up with meaningful and simple names. I'm not quite sure about this - using the same name, since it's a constant, is a little problematic. I have a solution with a proxy class but I don't think this is the optimal solution. I was considering using variables (with the let method) like "taskModel", but it seemed a little verbose and unusual.
One other option that comes to mind, but I am not sure is possible to do easily, is to remove an existing association and then define a new one. So e.g. add a has_many and then remove it, add a habtm...
How would you go about doing this?
Defining unique models in the spec files is not necessarily a bad idea since it makes it easy to see exactly how each model is defined. The obvious problem with this approach is if you want to reuse the models in other test files. The Rails approach to this is to define all the models in separate files and then just require them in the tests that need it.
I think it really just depends on how many models you have and how much you want to reuse. In one of my gems, I took the approach of defining the models in the spec file, in another gem, I defined them in the spec helper, and in yet another I took the Rails approach and used a separate directory for them. If you asked me which one I preferred, I'd probably go with the spec that also contains the models because it's all in one place. Definitely a subjective problem though.
Another approach I've taken on occasion is to create an anonymous class that's guaranteed to only be around for the life of that test:
describe 'my test' do
let(:my_class) do
Class.new(Task) do
has_many :things
belongs_to :something_else
end
end
it 'should have many things' do
my_class.should have(100).things
end
end

RoR: How to use routes to filter refinerycms backend content?

everyone. I'm new to refineryCMS( and rails also). I summed up my question in the end of this article in case the problem description is too long.
Here is my question:
How do I use routes( or namespace) to filter backend contents?
For example, I have several departments on my site. They have similar structures, yet the contents are different. I want to manage them separately. Say, I have department ABC and department EFG and department MAIN, I want to manage them through /refinery/ABC and /refinery/EFG and /refinery(/MAIN).
How can I achieve something like this?
Currently I've two ideas, but not knowing how to implement.
First, I may create each department as rails engine and then mount them on the main_app. However, I don't like this solution because it will duplicate many almost identical tables since each department's structure are quite similar. And I'm not familiar with creating engine, worrying about the performance.
Second way I've thought out is to make every Refinery::Pages, resource and custom engine model belongs to certain department. And then I could write a controller to filter all those thing out by specifying which department like I mentioned above "/refinery/:department".
In short, I prefer the second way, though I don't know how to:
make every model(custom engine or Refinery native ones) belongs to department. Especially for Refinery native ones(resource, image, pages)
how to duplicate the admin rendering like refinery's default backend after controller has filtered content I want.
After some search up, I found that there are too many #variables to filter properly. Is there some easier way?
Thanks in advance!
Routes.rb
try put the:
get 'refinery/:dep' => 'refinery#deps'
then in refinery controller your put
def deps
dep = params[:dep]
*some code*
end

Clean up fat rails helpers

Today, trying to DRY up some code, I extracted some duplicate File.exists? code used by several helper methods into a private method
def template_exists?(*template) and accidently monkey patched this already existing Rails helper method. This was a pretty clear indicator of a code smell, I didn't need need any the inherited methods, yet I inherit them. Besides, what was my refactored method doing in this helper at all?
So, this helper does way too much and hence violates SRP (Single Responsibility Principle). I feel that rails helpers are inherently difficult to keep within SRP. The helper I'm looking at is a superclass helper of other helpers, counting 300+ lines itself. It is part of a very complex form using javascript to master the interaction flow. The methods in the fat helper are short and neat, so it's not that awful, but without a doubt, it needs separation of concerns.
How should I go forth?
Separate the methods into many helpers?
Extracting the code inside the helpers methods into classes and delegate to them? Would you scope these classes (i.e. Mydomain::TemplateFinder)?
Separate the logic into modules and list them as includes at the top?
other approaches?
As I see, no 2 is safer wrt accidential monkeypatching. Maybe a combination?
Code examples and strong opinions appreciated!
Extracting helpers methods into classes (solution n°2)
ok to address this specific way to clean up helpers 1st I dug up this old railscast :
http://railscasts.com/episodes/101-refactoring-out-helper-object
At the time it inspired me to create a little tabbing system (working in one of my apps in conjunction with a state machine) :
module WorkflowHelper
# takes the block
def workflow_for(model, opts={}, &block)
yield Workflow.new(model, opts[:match], self)
return false
end
class Workflow
def initialize(model, current_url, view)
#view = view
#current_url = current_url
#model = model
#links = []
end
def link_to(text, url, opts = {})
#links << url
url = #model.new_record? ? "" : #view.url_for(url)
#view.raw "<li class='#{active_class(url)}'>#{#view.link_to(text, url)}</li>"
end
private
def active_class(url)
'active' if #current_url.gsub(/(edit|new)/, "") == url.gsub(/(edit|new)/, "") ||
( #model.new_record? && #links.size == 1 )
end
end #class Workflow
end
And my views go like this :
-workflow_for #order, :match => request.path do |w|
= w.link_to "✎ Create/Edit an Order", [:edit, :admin, #order]
= w.link_to "√ Decide for Approval/Price", [:approve, :admin, #order]
= w.link_to "✉ Notify User of Approval/Price", [:email, :admin, #order]
= w.link_to "€ Create/Edit Order's Invoice", [:edit, :admin, #order, :invoice]
As you see it's a nice way to encapsulate the logic in a class and have only one method in the helper/view space
You mean seperate large helpers into smaller helpers? Why not. I don't know your code too well, but you might want to consider outsourcing large code chunks into ./lib.
No. ;-) This sounds awfully complex.
Sounds complex too. Same suggestion as in 1.: ./lib. The modules in there are auto-loaded if you access them.
No
My suggestion is: Hesitate from using too many custom structures. If you have large helpers, ok, might be the case. Though I wonder if there is an explanation why that whole helper code is not in the Controller. I use helpers for small and simple methods that are used inside the template. Complex (Ruby-)logic should be put into the Controller. And if you really have such a complex Javascript app, why don't you write this complex stuff in Javascript? If it really has to be called from the template, this is the way to go. And probably makes you website a bit more dynamic and flexible.
Regarding monkey patching and namespace collisions: If you have class name, method names etc. that sound common, check out if they are defined. Google, grep or rails console for them.
Make sure you understand which code belongs to
Controller: Fill variables with stuff, perform user actions (basically the computation behind your page)
Helper: Help doing simple stuff like creating a fancy hyperlink
def my_awesome_hyperlink url, text
"Fancy Link to #{text}"
end
./lib: More complex stuff that is used by more than one Controller and/or also used directly by other components like Cucumber step definitions
inside the Template as Ruby Code: Super easy to read
inside the Template (or ./public) as Javascript code: Matter of taste. But the more dynamic your app, the more likely code belongs in here.
Ok this is a really hard question to answer. Rails kind of leads you down the path of view helpers and really doesn't give you a decent baked-in alternative when you out-grow it.
The fact that helpers are just modules that are included in to the view object doesn't really help with the separation of concerns and coupling. You need to find a way to take that logic out of modules altogether, and find it a home in its own class.
I'd start by reading up on the Presenter pattern, and try to think of how you might be able to apply it as a middle layer between the view and the model. Simplify the view as much as possible, and move the logic to the presenter or the model. Move javascript right out of the view, and instead write unobtrusive javascript in .js files that enhance the functionality of the existing javascript. It definitely does not need to be in the view, and you'll find that helps clean up a lot if stuffing js in your views is what got you in this mess.
Here's some links for reading:
http://blog.jayfields.com/2007/03/rails-presenter-pattern.html
About presenter pattern in rails. is a better way to do it?
http://blog.jayfields.com/2007/01/another-rails-presenter-example.html
http://blog.jayfields.com/2007/09/railsconf-europe-07-presenter-links.html
Don't get too caught up in the specific code examples, rather try to understand what the pattern is trying to accomplish and think how you could apply it to your specific problem. (though I really like the example in the 2nd link above; the stack overflow one).
Does that help?
It is difficult to suggest a clear solution without the code. However since helper methods all live in the same global view instance, name collision is a common problem.
#Slawosz may be a solution but no really fit for the helpers philosophy.
Personally I would suggest to use the cells gem : cells are like component for rails, except lightweight, fast, cacheable and testable.
Also to answer your specific problem they're completely isolated. When your view helpers get to complex they're definitely the solution.
(disclosure I am not the creator of this gem, just happily using it....)
# some view
= render_cell :cart, :display, :user => #current_user
# cells/cart_cell.rb
# DO whatever you like in here
class CartCell < Cell::Rails
include SomeGenericHelper
def display(args)
user = args[:user]
#items = user.items_in_cart
render # renders display.html.haml
end
end
Also you can use a generic helper for dryness here without fearing name clash.
I would create a small library which is responsible to manipulate yours forms.Some well named classes, some inheritance, and as input you pass ie parameters, and as output you can has ie. objects for partials used in this form. Everything will be encapsulated, and it will be easy to test.
Look at AbstractController code, and then Metal to see how smart are rails designed, maybe there You will find inspiration how to solve your problem.
Your approach is correct but I would prefer 3rd point i.e. separate the logic into modules.
Modules open up lots of possibilities, particularly for sharing code among more than one class, because any number of classes can mix in the same module.
The greatest strength of modules is that they help you with program design and flexibility.
Using such kind of approach you can achieve design patterns.

In Rails 3.0, is there a way for UrlHelper's path method output a nested-resource's route without explicitly specifying the parent?

Let's say I have this setup: An Area has many :places
The routes.rb is something like:
resources :areas, :path=>"/" do
resources :places, :path=>'/places'
end
And so let's say I have the area "Midwest" and the place "Chicago"...to get to the Chicago place page, I do:
area_place_path(place, place.area)
I would really prefer a method that would be able to guess the place's area (since it's a many-to-one relationship) without having to explicitly pass it in as an argument. I know how to write one custom for my specific needs, but I was wondering if there was a magic Rails way that I'm ignorant of?
It seems like there should be a magic Rails way but there isn't. Such a feature can be added in theory but if you read the related Rails code you'll find that such a feature would be a violation of separation of concerns (UrlHelper is part of ActionView but this functionality would need to be aware of ActiveRecord associations) so I don't think this feature will be added any time soon if ever. I personally don't see any harm in writing your own path helpers and a path helper to give you this functionality would be trivial to write. My suggestion is to just write your own path helper. There really should be an easier way (a plugin perhaps?).

Resources