How do i determine what goes in the model vs controller? - ruby-on-rails

This is my most confused aspect that I continually have to ask people about. They have given me answers like 'if it works with data it goes in the model'... but to me that is pretty much ALL of it.
Does anyone have a better way to explain this?
Perfect example from my current code:
I have a listing of posts that can be favorited or not favorited. On the front end, i differentiate the different ones by dynamically adding class="favorite" to the HTML depending on if its a favorite or not.
So basically ... <li class="item<%= is_favorite?(current_user.id) %>">
Part of me thinks this should go in the model because its going to be running a statement to find a record that matches :resource_id and :user_id...
but another part of me thinks its going to be in the controller because its directly outputting the word " favorite" which is used in html
My second mini question is, is it the-rails-way to put methods that the controller uses in the same controller? as long as they remain un-routed, etc. Or is that not the right spot?

You're thinking properly.
The right answer is that you should use presenters or decorators.
See this railscast for inspiration.

Related

angular dart >> Best way to create a table:column renderer

I'm hopping this awesome community can steer me on the right direction. I came from the flash/flex/js world, and I like how simple it is to define an item renderer in flex. Here is what I'm trying to accomplish:
I have an Angular component which consist of a form and a html table. I have the columns, headers, rows, etc. all populating correctly using ng-repeat. I want to be able to define column "renderers", so if someone passes me a column property like "renderAs: 'button'" or "renderAs: 'progress'" I should be able to render the entire column as a button, or progress bar, etc.
Here is what I've tried so far:
ng-bind-html="getColRenderer(column.renderAs, column.value)" which
returns HTML based on 'renderAs'. As you all probably know, this
will only work with basic HTML stuff, but I cannot append an
'ng-click', or an 'href' due to angular's security. So, I opted
for something else.
I semi-have a good solution embedding a "ng-switch" inside my
ng-repeat. I had an ng-if but with several types of potential
"renderers" I opted for the switch. This somehow seems like future
problems while trying to display too many columns or rows, just my
fears.
Decorators - I like decorators, but it seemed a bit too much for
something as a simple button that calls something on click or a
progress bar with 2 values. So, I halted going into this path, but
if this is the shinning path all walk, then by all means.
I hope someone out there has ran/done something like this and can steer me on the right course of action. If the ng-switch or ng-if is okay, then I'm good to go.
Once again, thank you in advanced.

Angular: Input with model binding acts on keypress, only when there's no controller

Angular newb here, thoughts appreciated...
Say I want an input field to control the window title as you type. A field with a model binding and no associated controller acts on keypress, as intended. However, there has to be a bit more logic to it -- default value before any user input, also used if the input is blanked.
Adding a controller bound to enclosing elements gives a place for that logic, but the change-on-keypress behavior is gone. I'm sure it's possible to recreate it by hand or with ui, but since it's inherently there without the controller, I'm wondering if I'm missing the simple clean way.
Simple version, acts on keypress, but with no smarts:
<title ng-bind-template="{{windowTitle}}">Default Title (not seen)</title>
<input ng-model="windowTitle" type="text">
Putting controller bindings on the head (for the title) and a containing div (for the input), and setting a default $scope.windowTitle inside the controller function does use that default value, but it breaks the auto-update.
I know in real life you'd want a real model, but what I'm really trying to understand is these two ways angular appears to work. I haven't found anything specifically describing two different implicit input binding behaviors, but I haven't been through all the docs yet.
How should I be thinking about this?
Edit: It's not the window title or default value per se that I'm interested in. I'm trying to understand this:
When there's no controller on either the field or the title, typing in the field changes the window title immediately, on keypress. The title is directly linked to the field value, with no other angular hookup.
With controller bindings around the title and the field, typing in the field has no effect on the title.
What I've since realized (I think) is that ng-controller bindings create a new instance of the controller each time. Here's the non-working code I didn't show before:
<title ng-controller="TitleCtrl" ng-bind-template="{{windowTitle || 'Foo'}}">Foo</title>
...
<label ng-controller="TitleCtrl">
<input ng-model="windowTitle" type="text">
{{windowTitle}}
</label>
The value set by the model binding to the field is shown correctly within that instance of that controller, and updates on keypress, as before. But since those two controller instances are separate, the binding to the title works but the data it points to isn't bound to the field.
Isn't that right? The reason it works with no controllers is that that makes the value global, so the title binding sees the value set by the field binding.
So what's the canonical way to reference data from some other area? Create a service?
I realize that this is basic angular stuff, just getting started here, so thanks!
Edit 2
On reflection, I've come to seriously disrespect this whole question, even though I wrote it.
It's based on way-too-early poor understanding of the Angular application model. I had worked through only part of the official tutorials, and jumped ahead to removing all the js from a not big but not totally trivial existing app, and exploring what Angular could to in that context.
I got some very quick bang for the buck, getting several pieces of functionality working with very little code, and simple, clear markup, felt good. But I really had short-circuited internalizing the Angular way of thinking, and my quick and dirty no-architecture approach broke down when different parts of the page needed to coordinate with each other, as in this question.
I've postponed that project while I go back to tutorials and other learning. If other folks think this question should be deleted, I'd add my vote. Or maybe it's a useful on some level, ignorant though it is.
Well, there are multiple ways to achieve the behavior you want without using an explicit controller and model, you could:
<title ng-bind-template="{{windowTitle && windowTitle || 'default'}}"></title>
Or in a more simple way:
<title>{{windowTitle && windowTitle || 'default' }}</title>
In both cases, we're using the conditional expression:
(condition) && (answer if true) || (answer if false)
You should however strive to remove logic from the templates.

SEO: URL for detail page, include categories or not?

I'm working on a new advert website and want to implement some good SEO URLs.
I got category URLs like:
/category
/category/sub-category
This seems ok. What about detail pages?
Option 1:
/announcements-and-notices/announcements-various/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
Option 2:
/adverts/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
In reality my website has a pretty long URLs due to multiple areas you can shop. So it would become:
/en/area-name/announcements-and-notices/announcements-various/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
/en/area-name/adverts/15880/suscipit-dis-molestie-malesuada-vestibulum-ut.html
Which detail page would be a better URL? The first option seems to be better if the product has no long/good title. The second seems better as its the most relevant one and shortest especially with long category names.
I would like to hear your thoughts!
EDIT:
I found this two google docs:
http://www.google.nl/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDYQFjAA&url=http%3A%2F%2Fwww.google.com%2Fwebmasters%2Fdocs%2Fsearch-engine-optimization-starter-guide.pdf&ei=lXyaT6T_L8zR4QSM4c2qDw&usg=AFQjCNEMj8KHxhxQz9cMLoMxMDiLdrAbJw
http://support.google.com/webmasters/bin/answer.py?hl=en&answer=76329
I think I will be going for /adverts. Anyone disagree?
i have seen many of SEO analysts miss something about optimizing their webpage and that is your page will be optimized for only some keywords not all keywords. it is not important how length is your URL. you should first analyze whether the contents in your webpage is rich enough to have such URL with these keywords or not. if the answer for every keyword is yes then the more length will give you the more rank.
I think you can even set your pages up in a way to use only the slug and skip the id, such as:
/adverts/suscipit-dis-molestie-malesuada-vestibulum-ut
or even just:
/suscipit-dis-molestie-malesuada-vestibulum-ut
like this and refer straight to the adverts controller and the advert itself, which has this slug assigned to it (the one with id 15880).
This way you'll have nice and clean URLs. Just assign and keep an unique slug for each advert and handle it using .htaccess, or dynamically inside the code of your site, if the system allows it.
Cheers.

How to create a tagging system like on Stack Overflow or Quora

I want to create a tagging system like seen here on Stack Overflow or on Quora. It'll be its own model, and I'm planning on using this autocomplete plugin to help users find tags. I have a couple of questions:
I want tags to be entirely user-generated. If a user inputs a new tag by typing it and pressing an "Add" button, then that tag is added to the db, but if a user types in an existing tag, then it uses that one. I'm thinking of using code like this:
def create
#video.tags = find_or_create_by_name(#video.tags.name)
end
Am I on the right track?
I'd like to implement something like on Stack Overflow or Quora such that when you click a tag from the suggested list or click an "Add" button, that tag gets added right above the text field with ajax. How would I go about implementing something like that?
I know this is kind of an open-ended question. I'm not really looking for the exact code as much as a general nudge in the right direction. Of course, code examples wouldn't hurt :)
Note I am NOT asking for help on how to set up the jQuery autocomplete plugin... I know how to do that. Rather, it seems like I'll have to modify the code in the plugin so that instead of the tags being added inside the text field, they are added above the text field. I'd appreciate any direction with this.
mbleigh's acts_as_taggable_on gem is a feature-complete solution that you should definitely look into a little more closely. The implementation is rock-solid and flexible to use. However, it is mostly concerned with attaching tags to objects, retrieving tags on objects, and searching for tagged items. This is all backend server stuff.
Most of the functionality you are looking to change (based on your comments) is actually related more to your front-end UI implementation, and the gem doesn't really do much for you there. I'll take your requests one-by-one.
If user inputs a new tag, that tag
gets added, if user inputs an
existing tag, the existing tag gets
used. acts_as_taggable_on does this.
Click a tag from suggested list to
add that tag. This is an
implementation issue - on the
back-end you'll need to collect the
suggested list of tags, then display
those in your presentation as links
to your processing function.
Autocomplete as user enters
potential tag. You'll use the jQuery
autocomplete plugin against a list
of items pulled off the tags table.
With additional jQuery, you can
capture when they've selected one of
the options, or completed entering
their new tag, and then call the
processing function.
Restrict users to entering only one
tag. This will be your UI
implementation - once they've
entered or selected a tag, you
process it. If they enter two words
separated by a comma, then before or
during processing you have to either
treat it as one tag, or take only
the text up to the first comma and
discard the rest.
When you process the addition of a
tag, you will have to do two things.
First, you'll need to handle the UI
display changes to reflect that a
tag has been entered/chosen. This
includes placing the tag in the
"seleted" area, removing it from the
"available" display, updating any
counters, etc. Second, you'll need
to send a request to the server to
actually add the tag to the object
and persist that fact to the
database (where the taggable gem will take over for you). You can either do this via
an individual AJAX request per tag,
or you can handle it when you submit
the form. If the latter, you'll need
a var to keep the running list of
tags that have been added/removed
and you'll need code to handle
adding/removing values to that var.
For an example of saving tags while editing but not sending to server/db until saving a form, you might take a look at the tagging functionality on Tumblr's new post page. You can add/remove tags at will while creating the post, but none of it goes to the database until you click save.
As you can see, most of this is on you to determine and code, but has very little to do with the backend part. The gem will take care of that for you quite nicely.
I hope this helps get you moving in the right direction.
The more I try to force the acts-as-taggable-on gem to work the more I think these are fundamentally different types of problems. Specifically because of aliases. The gem considers each tag to be its own special snowflake, making it difficult to create synonyms. In some cases it doesn't go far enough, if you want the Tag to have a description you'd need to edit the given migrations (which isn't hard to do).
Here's what I'm considering implementing, given the trouble I've had implementing via the gem. Let's assume you want to create a tagging system for Technologies.
Consider the following psuedo code, I haven't yet tested it.
rails g model Tech usage_count::integer description:text icon_url:string etc. Run the migration. Note the
Now in the controller you will need to increment usage_count each time something happens, the user submits a new question tagged with given text.
rails g model Name::Tech belongs_to:Tech name:string
Name::Tech model
belongs_to :tech
end
Then you could search via something like:
search = Name::Tech.where("name LIKE :prefix", prefix: "word_start%")
.joins(:tech)
.order(usage_count: desc)
.limit(5)
This is starting point. It's fundamentally different from the gem, as each tag is just a string on its own, but references a richer data table on the back end. I'll work on implementing and come back to update with a better solution.

Does this Rails 3 Controller method make me look fat?

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.

Resources