Does this Rails 3 Controller method make me look fat? - ruby-on-rails

This is a new application, and I have an index method on a Search controller. This also serves as the home page for the application, and I'm trying to decide if I am headed down the wrong path from a design pattern perspective.
The method is already 35 lines long. Here is what the method does:
3 lines of setting variables to determine what "level" of hierarchical data is being searched.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
A 10 line section to redirect to one of two pages based on:
1) If the user does not have access, and is signed in, and has not yet requested access, tell them "click here to request access to this brand".
2) If the user does not have access, is signed in, and has already requested access, tell them "so and so is reviewing your request".
Another 10 lines to build the dynamic arel.
I can't get it straight in my head how to separate these concerns, or even if they should be separated. I appreciate any help you can offer!

Summarizing what you've said in something codelike (sorry, don't know ruby; consider it pseudocode):
void index() {
establishHierarchyLevel();
if (requestIncludedSubdomain())
fillSubdomainFields();
else
fillNonsubdomainFields();
if (user.isSignedIn() && !user.hasAccess()) {
if (user.hasRequestedAccess())
letUserIn();
else
adviseUserOfRequestUnderReview();
}
buildDynamicArelWhateverThatIs();
}
14 lines instead of 35 (of course, the bodies of the extracted methods will lengthen the overall code, but you can look at this and know what it's doing). Is it worth doing? That really depends on whether it's clearer to you or subsequent programmers. My guess is it's worth doing, that splitting out little code blocks into their own method will make the code easier to maintain.

That's a lot of variables being set. Maybe this is a good opportunity for a module of some kind? Perhaps your module can make a lot of these decisions for you, as well as acting as a wrapper for a lot of these variables. Sorry I don't have a more specific answer.

Without your code it's somewhat difficult to suggest actual fixes, but it definitely sounds like a really wrong approach and that you're making things much harder than they need to be:
3 lines of setting variables to
determine what "level" of hierarchical
data is being searched
if there is a search form, I would think you would want to pass those straight from the params hash into scopes or Model.where() calls. Setup scopes on your model as appropriate.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
This seems to me like it should be at most 1 line. or that in your view, you should use if statements to change what you'd like your output to be depending on your subdomain.
A 10 line section to redirect to one of two pages based on:
the only thing different in your explanation of the 2 views is "whether the user has requested access" surely this is just a boolean variable? You only need 1 view. Wrap the differences into 2 partials and then in your view and write one if statement to choose between them.
Another 10 lines to build the dynamic arel.
It might be necessary to go into Arel, but I highly highly doubt it. Your actual search call can in most cases (and should aim to be) 1 line, done through the standard ActiveRecord query interface. You want to setup strong scopes in your models that take care of joining to other models/narrowing conditions, etc. through the ActiveRecord Query interface.

Related

Trick when dynamically appending GET attributes

When dynamically building SQL queries you often see something like this:
WHEN 1=1 AND title="Example" AND ...
The purpose of the 1=1 is to be able to keep appending AND-statements without having to check if any previous statements exist. Thereby avoiding something like this happening:
WHEN AND title="Example" AND ...
I quite often come across a related issue when building the the attributes/search-query for a GET request. I don't want to keep checking if I need to prepend the attribute with '?' or '&'.
So my question is, is there any 'safe' way for me to add an initial attribute that won't interfere with any potential software on the server side. Assuming I do not have full knowledge of the backend.
Something like:
http://example.com?1=1&title=example
http://example.com?null&title=example
http://example.com?i-am-useless&title=example
Or is this allowed?
http://example.com?&title=example
Is there perhaps a simpler way to solve this?
Make sure the URI-string you want to add parameters to already ends in a '?'. Then for every key-value pair, add 'key=value&' to it. Optionally you can then in the end delete the last character from the resulting string. - Reddit user omepiet

Is there a best method to evaluate URL variables to determine the appropriate page?

I am using ColdFusion 9.0.1.
I have a new web site that uses Bikes.cfm and Makers.cfm as template pages. I need to be able to pass BikeID and MakerID to both of the these pages, along with other variables. I don't want to use the Actual page name in the URL, such as this:
MyDomain.com/Bikes.cfm?BikeID=1234&MakerID=1234
I want my URL to look more like this:
MyDomain.com/?BikeID=1234&MakerID=1234
I need to NOT specify the page name in the URL.
I want these two URLs to access different data:
MyDomain.com/?BikeID=1234&MakerID=1234 // goes to bike page
MyDomain.com/?MakerID=1234&BikeID=1234 // goes to maker page
So, if BikeID appears in the URL before MakerID, go to the Bikes.cfm page. If MakerID appears before BikeID, go the Makers.cfm page.
Is there an easy and existing method to arrange the URL keys in such a way to have them point to the appropriate page?
Should I just parse the the URL as a list and determine the first ID and go to the appropriate page? Is there a better way?
Any thoughts or hints or ideas would be appreciated.
UPDATE -- It certainly appears that using the order of parameters in a URL is a bad idea for the following reasons:
1) many programs append variables to the URL
2) some programs may reorder the variables
3) GoogleBot may not consider order relevant and will most likely not index the site correctly.
Thanks to everyone who provided advice in a positive manner that my approach was probably a bad idea and would not produce the results I wanted. Thanks to everyone who suggested alternate means to produce the results I wanted.
If anyone of you positive people would like to put your positive comment/advice as an answer, I'd be happy to accept it as the answer.
Despite my grave misgivings about the whole idea, here's how I would do it if I were forced to do so:
index.cfm:
<cfswitch expression="#ListFirst(cgi.query_string, '=')#">
<cfcase value="BikeID">
<cfinclude template="Bikes.cfm">
</cfcase>
<cfcase value="MakerID">
<cfinclude template="Makers.cfm">
</cfcase>
<cfdefaultcase>
<cfinclude template="Welcome.cfm">
</cfdefaultcase>
</cfswitch>

grails - ways to set up a replicated site?

I've got a need where each user can customize their own page on a replicated site. In grails it seems the most straightforward way to do this is:
somedomain.com/someController/JohnDoe
spelling out a controller, except this forces folks to type in a longer domain name, versus something like
somedomain.com/JohnDoe
Using sub-domains may be another approach, however they would need to be created automatically, i.e. when someone joins.
Can you please clarify the main ways Grails supports this kind of requirement/need (replicated site), and some of the pros/cons of each?
Thanks, Ray
Edit: Per Tomasz's edit below, the simplest course of action isn't clear. If you have insights on this please do share.
It is called UrlMappings in grails. You need to declare:
"/$username?" {
controller = 'someController'
action = 'user'
}
It redirects to someController, action user and optional variable called username.
This solution has one catch. Every one level path you visit passes this rule and takes you to someController. You cannot go to somedomain.com/books because it passes rule above and it follows you to someController#user with params['username']='books'. Then you can't use default actions. But if you decide that all your other paths have at least one slash, e.g. /books/list then you can follow this solution
Edit: I was wrong. It doesn't work as I've expected. I thought that UrlMappings are applied in order they are defined. That's not true, as explained here. Even worse - it's not documented (GRAILS-6246). Most specific explanation comes from Peter Ledbrook :
It uses a specificity algorithm, so the most specific match should apply
You must experiment then. I suggest you use safest solution and stick with /user/username solution.

ASP.NET Routing Question

Why is this:
http://MySite.com/Project/24/Search/32/Edit/49
preferred over this?
http://MySite.com/Project/24?Search=32&Edit=49
I'm not sure where your premise is coming from? It looks like an artificial example, which makes it hard to comment on.
A better comparison would be something like:
http://MySite.com/Project/24/Members/Edit
As opposed to:
http://MySite.com/Projects.aspx?id=24&section=Members&action=Edit
Where, among other things, the hierarchy of entities is immediately obvious from the first example (ie, a Project contains Members). It also suggests that you can use other URLs that contain similar structures to the first (ie, /Projects/24 and /Projects/24/Members), so in that sense it's more concise.
If it comes down to actions that have a variable number of parameters, such as searching, then it's totally fine to use URL parameters as this will give you more flexibility, eg:
http://MySite.com/Projects/Search?name=KillerApp&type=NET
You could construct a URL using the first style, but you don't really gain anything, and managing the route could add unnecessary overhead:
http://MySite.com/Projects/Search/name/KillerApp/type/NET
I would argue that this (or any similar construction, eg if you removed the param names) suffers from an artificial hierarchy - the action in this case is really Search, and everything else is just a parameter of the Search, so it's in the same hierarchy, not some "sub" hierarchy.
Not really a fair comparison. The style allows you to drop the GET parameter names, so the routed one should read something like
http://MySite.com/Project/24/32/49
It's really an aesthetic improvement, though -- it's both neater-looking, and easier to type or read out to someone.
Its mostly a human readability issue, although (since most search engine ranking algorithms are not publically disclosed), it is believed to have SEO value as well.
In the example case, it may not be any better. But it's a Search Engine Optimization in general. Here are some SEO best practices -- from that article ...
Ideally, the URL structures should be
static, and reveal what the page is
about. A simple and clear URL
structure is much easier for both
search engine spiders and human
beings.
Easier to remember as well. It's easier for a user to remember /Employee/1 to get the information for employee #1 rather than understand a querystring. Not a reason to use it but I think its a small improvement.

Rails dashboard design: one controller action per div

I am implementing a dashboard as a relative Rails newbie (more of an infrastructure guy). The dashboard will consist of multiple pages, each page of which will contain multiple charts/tables/etc. For modularity, I want it to be as easy as possible to add new charts or change views of the data.
Say one page has 5 different charts. I could have the controller do 5 separate data lookups, hold all the relevant data in instance variables, and render 5 partials, each of which touch subsets of the data. But it seems more modular to have one "index" controller action whose render has a bunch of divs, and for each div there is another controller action which does the data lookup and has an associated view partial in charge of managing the view of that data within the div.
So if I'm showing the website dashboard page which has two graphs, website/index would use website/graph1 and website/graph2 to look up the data for each and then _graph1.html.erb and _graph2.html.erb would use the controller data to fill out divs "graph1" and "graph2", etc.
Is this the right design, and if so, what's the easiest way to accomplish this? I have an approximation using remote_function with :action => "graph1" to fill out divs, but I'm not 100% happy with it. I suspect I'm missing something easier that Rails will do for me.
Version 1:
Simple method that I've actually used in production: iframes.
Most of the time you don't actually care if the page renders all at once and direct from the server, and indeed it's better for it to load staggered.
If you just drop an iframe src'd to the controller's show action, you have a very simple solution that doesn't require direct cross-controller interactions.
Pro:
dead easy
works with existing show actions etc
might even be faster, depending on savings w/ parallel vs sequential requests and memory load etc
Cons:
you can't always easily save the page together with whatever-it-is
iframes will break out of the host page's javascript namespace, so if they require that, you may need to give them their own minimalist layout; they also won't be able to affect the surrounding page outside their iframe
might be slower, depending on ping time etc
potential n+1 efficiency bug if you have many such modules on a page
Version 2:
Do the same thing using JS calls to replace a div with a partial, à la:
<div id="placeholder">
<%= update_page {|page| page['placeholder'].replace with some partial call here } %>
Same as above, except:
Pro:
doesn't lock it into an iframe, thus shares JS context etc
allows better handling of failure cases
Con:
requires JS and placeholder divs; a bit more complex
Version 3:
Call a whole bunch of partials. It gets complicated to do that once you're talking about things like dashboards where the individual modules have significant amounts of setup logic, however.
There are various ways to get around this by making those things into 'mixins' or the like, but IMO they're kinda kludgy.
ETA: The way to do it via mixins is to create what is essentially a library file that implements your module controllers' setup functions, include that wherever something that calls 'em is used, and call 'em.
However, this has drawbacks:
you have to know what top level controller actions will result in pages that include those modules (which you might not easily, if these are really widgety things that might appear all over, e.g. user preference dependent)
it doesn't really act as a full fledged controller
it still intermixes a lot of logic where your holding thing needs to know about the things it's holding
you can't easily have it be segregated into its own controller, 'cause it needs to be in a library-type file/mixin
It IS possible to call methods in one controller from another controller. However, it's a major pain in the ass, and a major kludge. The only time you should consider doing so is if a) they're both independently necessary controllers in their own rights, and b) it has to function entirely on the back end.
I've had to do this once - primarily because refactoring the reason for it was even MORE of a pain - and I promise you don't want to go there unless you have to.
Summary
The best method IMHO is the first if you have complex enough things that they require significant setup - a simple iframe which displays the module, passing a parameter to tell it to use an ultraminimalist layout (just CSS+JS headers) because it's not being displayed as its own page.
This allows you to keep the things totally independent, function more or less as if they were perfectly normal controllers of their own (other than the layout setting), preserve normal routes, etc.
If you DON'T need significant setup, then just use partials, and pass in whatever they need as a local variable. This will start to get fragile if you run into things like n+1 efficiency bugs, though...
why don't you give Apotomo a try, that's stateful widgets for Rails:
A tutorial how to build a simple dashboard
You could achieve this by using
render_output = render :action => "graph2"
But Me personally would probably wrap the code in either a shared helper or write you own "lib" under the lib directory to reuse the code with a shared template. Remember that unless you change your route.rb file any public method defined is accessible by
/controller/action/:id
Also remember to turn off the layout for the function :layout => nil (or specify at the top of the controller layout "graph", :except => ["graph2"]
Cheers
Christian
I'm not aware of any special Rails tricks for achieving this without using AJAX in the way you've outlined.
The simplest way to get the modularity you seek is to put those portions of controller code into separate methods (e.g. set_up_graph1_data, set_up_graph2_data, etc.), which you simply call from your index action to set up the variables for the view.
You can put these methods into ApplicationController if you want them available to multiple controllers.
As a side note, early on, Rails did used to have a feature called 'components' which would allow you to do exactly what you're asking for here, without having to use AJAX. From your view, you could just render another controller action, inline. However, this feature was removed for performance and design philosophy reasons.

Resources