Where to place common logic with RoR - ruby-on-rails

I have a model Project that appears in multiple controllers in an application I'm building as it appears on multiple pages. The where clause for this isn't complicated, per se, but I feel like it is too large to be repeated on every method requiring projects with these constraints.
My question is, where, if possible, does this common call for Projects go? In .NET, I'd have a ProjectService class with a method that would return all projects, and another that returned all projects that satisfied my conditions. I'm new to Rails so I'm struggling to see where this fits in?

You can either use a class method or Scopes.
class Project < ActiveRecord::Base
# example for a scope
scope :awkward_projects,where(awkward: true)
# example for a class method.
def self.awkward_projects
where(awkward: true)
end
end
Its very safe to do what was once given in a SO answer. Read below and choose carefully.
Quoting an answer
"Generally, I use scope entries for simple one-liners to filter down my result set. However, if I'm doing anything complicated in a "scope" which may require detailed logic, lambdas, multiple lines, etc., I prefer to use a class method. And as you caught, if I need to return counts or anything like that, I use a class method."

Related

How to use two concerns with the same name?

I want to use concerns app/controllers/concerns/likeable.rb and app/models/concerns/likeable.rb.
The first one goes to controllers and the second one goes to models.
If I create two files, only the first one is loaded.
What's the best way to solve this problem?
I didn't find a way to use controller and model concerns with the same name without any namespaces.
So, my final solution is to use LikeableModel and LikeableController concerns.
I had the same problem but I was able to resolve it by namespacing the controller and model concerns. I moved all model concerns to app/models/concerns/models/ and all controller concerns to app/controllers/concerns/controllers/. With this, it's possible to have model and controller concerns with the same name.
app/models/concerns/models/likeable.rb
module Models::Likeable
end
app/controllers/concerns/controllers/likeable.rb
module Controllers::Likeable
end
The concerns can be included like this;
class Post < ActiveRecord::Base
include Models::Likeable
end
class PostsController < ApplicationController
include Controllers::Likeable
end
Older question, but I thought I'd throw in another option that I believe fits in with Rails conventions a little neater. The Likeable namespace is responsible for dealing with any items that are likeable, and there are controllers that need to deal with building responses for likeable resources, and models for those likeable resources. Both of these can implement aspects of the Likeable concept. What is needed is a breakdown within that namespace of the different responsibilities.
What I would do in this case is create a file in app/controllers/concerns/likeable/respondable.rb that implements the Likeable::Respondable functionality that a Controller provides. (You may find a better name than Respondable for your needs - for instance, if the controller concern only really handles some logic around params, you may call it Likeable::Paramable, etc.)
Similarly, if the model side of your Likeable scaffold has to do mainly with persistence logic, you might define a Likeable::Persistable module in app/models/concerns/likeable/persistable.rb.
In this way, you can still keep all your logic for likeables in a single namespace, and get more specific for your controller and model concerns.
What's nice about this approach is that you can easily add to the namespace later if you find a need for, say, a utility module or class that needs to live in the lib directory for dealing with special calculations or other shared functionality. In that case, you could easily define a Likeable::Utils module in lib/likeable/utils.rb, or something similar depending on the need, and everything will live under that one, consistent namespace.
You can disttingush two concerns with same name using namespace
Following is example
app/controllers/concerns/like/likeable.rb
module Like
class Likeable
# do some stuff here
end
end
app/models/concerns/likeable.rb
class Likeable
# do some stuff here
end

Does this method that changes an instance variable belong in my Rails controller or model?

I have a basic "best practice" question about controllers and instance variables.
Say you have an instance variable in anew or update action in a controller, is it ok to modify that instance variable via a private method in the controller? Or should the method exist in the model?
e.g. in this example below, I need to loop through the attributes of an instance variable, and add or remove something. For example, if I am using nested attributes 3 layers deep and have to remove certain attributes, change them and then add them back in. I know this may seem strange, but assume it is necessary.
def new
#some_thing = SomeThing.new(:some_params)
do_something_to_inst_var # method call
#some_thing.save
end
private
def do_something_to_inst_var
#some_thing.addresses.each do |address|
# modify it in some way
end
end
Or is this bad practice? Should this be a method in the model and should be called like:
#some_thing.do_something_to_inst_var
OR
should we explicitly pass the instance variable to the method like:
def new
#some_thing = SomeThing.new(:some_params)
do_something_to_inst_var(#some_thing) # method call
#some_thing.save
end
private
def do_something_to_inst_var(some_thing)
some_thing.addresses.each do |addresses|
# modify it in some way
end
end
I'm looking for some clarity here, with an example if possible. I'm still learning and trying to improve and I didn't find an answer by searching.
Rails applications should have "thin controllers" and "fat models" for a couple of reasons:
Each object should handle only its own responsibilities. A controller should just be about connecting the web, the the model and the view, which thanks to Rails doesn't take much code. If a controller method refers repeatedly to methods of the same model, it's incorrectly taking on model responsibilities; we say that it's not cohesive or that it has "Feature Envy". It is more likely that if the model changes the controller will have to change in parallel.
It's easier to test models than to test controllers.
Fix it by writing a method in the model that does the model-specific work and call it in the controller (your second option). (Eventually your model will get too fat and you'll have to break it up too, but that's another story.) For example:
class SomeThingsController
def new
#some_thing = SomeThing.new(:some_params)
#some_thing.do_something # method call
#some_thing.save
end
end
class SomeThing
def do_something
addresses.each do |address|
# modify it in some way
end
end
end
Regarding instance variables.
Define them only if necessary. Presumably the one in your example is needed for the view.
Assuming an instance variable is justified at all, there's no reason not to refer to it in private methods of the class that contains it. That's what they're for. So your first option (referring directly to the instance variable) is a bit better than your third option (passing it in). But, as discussed above, extracting a model method is better than both of the other two options.
In my opinion Modifying #instance_vars from private method is okay if your controller is just 100 lines long.
Imagine a scenario where there are 500 LOC in your controller and after a struggle of a couple of hours you found out that the #intance_var is being modified by some private method.
Helpful tips:
create small private methods with single responsibility
put ! at the end of method_name! indicating that it modifies something. Specially this is helpful when you see my_private_method!, ! makes you realize that its modifying something.
lets not put code in controller that do not belong here.
There is one more option:
In Controller:
def new
#some_thing = SomeThing.new(:some_params)
#some_thing_modified = #some_thing.modify_somehow(params)
#some_thing_modified.save
end
In SomeThing Model:
def modify_somehow(params)
result = self.clone
# ... modify result ...
return result
end
Because modify_somehow is now pure function (assuming you don't do anything in ... modify result ... part, that makes it impure), what you gain here is Referential transparency. Main benefit of referential transparency is that you can determine what function/method invocation will do, only by looking at its arguments, and get result of its work only via return value, and not via side effects. This makes your code more predictable, which in turn makes it easier to understand and debug.
There are of course disadvantages: Because you create new object this option can be less performant, it's also more verbose than its alternatives.
Functional programming concepts, like referential transparency, are not very popular in Rails community (probably because of how OO-centric Ruby is). But referential transparency is there if you want it, with its pros and cons.

Ruby on Rails ActiveRecord scopes vs class methods

Rails internally converts scopes to class methods then why can't we use class methods itself instead of going with scopes.
From the fine guide:
14 Scopes
[...]
To define a simple scope, we use the scope method inside the class, passing the query that we'd like to run when this scope is called:
class Article < ActiveRecord::Base
scope :published, -> { where(published: true) }
end
This is exactly the same as defining a class method, and which you use is a matter of personal preference:
class Article < ActiveRecord::Base
def self.published
where(published: true)
end
end
Note in particular:
This is exactly the same as defining a class method, and which you use is a matter of personal preference
And a little further (the Rails3 guide says the same thing here BTW):
14.1 Passing in arguments
[...]
Using a class method is the preferred way to accept arguments for scopes.
So which you use is a matter of preference and it is even recommended that you use class methods for scopes that take arguments.
Using scope is mostly a notational issue. If you say scope :whatever then you're explicitly saying that whatever is meant to be a query builder; if you say def self.whatever then you're not implying anything about the intent of the whatever method, you're just defining some class method that may or may not behave like a scope.
Of course, 14.1 makes a mess of this notational distinction by recommending that you not use scope when your scope takes arguments. Also keep in mind that in Rails3 you could say:
scope :published, where(published: true)
so an argumentless scope was visually "clean" and terse but adding a lambda to handle arguments would make it look messier:
scope :pancakes, ->(x) { where(things: x) }
But Rails4 wants lambdas even for argumentless scopes the distinction makes even less sense now.
I suspect that the difference is historical at this point. Scopes were probably something special back in the before times but became plain old class methods in the Rails3 era to cut down on duplication and to better mesh with the new query interface that came with Rails3.
So you can skip scope and go straight to class methods if you wish. You're even encouraged to do so when your scope takes arguments.
Scopes are just class methods.
Internally Active Record converts a scope into a class method.
"There is no difference between them" or “it is a matter of taste”. I tend to agree with both sentences, but I’d like to show some slight differences that exist between both.
This blogs explains the difference very well.

Proper organization of server side code?

I'm relatively new to rails, but I've made a few basic CRUD apps. However, this time, I'm making something different, and I'm not sure how to organize it.
It's essentially a one page app. The user fills out a form, and the code does some calculations based on those values. I have all the code written, but it's all just sitting in the controller. I'm assuming that this isn't correct.
There are two parts:
Using an external API, 2 constant arrays are generated. I need these variables to be global, or at least accessible for the calculator function.
I have a function that takes some inputs from the form that also calls other functions. A simplified version is below. I could put all the code into one function if that's necessary. I have them separate just so that the code is more readable.
def calc(input)
func1(input)
func2(input)
# do more stuff
return answer #I need to show this in the view
end
def func1(a)
end
def func2(b)
end
So, where should I put each part of this code?
To make your controllers thin, you can keep business logic at Service Objects.
Just create "services" directory at "app", add there some class like "user_searcher.rb".
And call it in the controller, passing all necessary data.
Such technique will help you to isolate business logic and incapsulate it in separate class.
BTW read this article http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
I think, from what I understand of you question, is this code should be placed in the helper classes. If you have dedicated class for this calculation, you can use class attributes to access array to access anywhere in the class or declare them constant, in case they are constant.
I don't think making global is a good practice, just because this is needed in some other function, instead return that variable and pass them as parameter where they are needed.

When should I use named scope and when class methods?

Which one would be preferable to use? Named scope or class methods? The use case is that the user selects a list box in the UI and based on the selected item, the table beneath it gets sorted. This functionality is across the application and is for many models.
The most important thing is that you do what feels right and that you're consistent with it. If something seems like it would be better in a method, use a method.
As of Rails 3, named scopes and class methods can function almost identically. However, the only "rules" I tend to follow when deciding on one or the other:
Use named scopes when an argument is NOT required
Use class methods when an argument is required
I also tend to use named scopes when I plan on chaining them together, as they tend to be short with minimal logic.

Resources