In case you were unaware, this is a beginner's question.
Having learned a bit of Ruby, I have ventured onto Rails, but have run into a brick wall when it comes to organizing methods. I'm building something which is supposed to take the data/parameters you get when someone creates something, but instead of showing it like you would a tweet or blog post, I want to use them as variables in some mathematical calculations, the results of which I then want to show.
Now, in Ruby, I would make a method for each little math operation, to make sure they (the methods) have a single responsibility each. In Rails, though, what am I supposed to do? In case you don't understand my problem, I think it has to do with my lack of understanding of instances in Rails. Instances in Ruby can call upon the methods I make, but where do I call upon my methods (actions?) in Rails?
You should follow the MVC paradigm:
The controller should receive the parameters that the user gave via some html form.
Then that controller should instantiate an object that is doing the math calculation and then the controller should render a view to present the results to the user.
The place where the controller and the views are stored is already decided by the framework:
controllers are in app/controllers and the views in app/views/<controller_name>
Now the question is where you put the class that performs the calculations.
You might think about the app/models folder, but that one is typically for the models that inherit from ActiveRecord::Base, ie, all those that are persisted in the database.
Normally the kind of class that you are implementing lives in the lib folder.
For example, you might have the following structure:
app/controllers/calculations_controller.rb
def perform_calculations
math_calculator = MathCalculator.new params[:operation]
#result = math_calculator.calculate
end
lib/math_calculator.rb
class MathCalculator
def calculate
# whatever you need to do here
end
end
app/views/calculations/perform_calculations.html.erb
<%= #result %>
There's nothing official, I think its helping you
http://www.caliban.org/ruby/rubyguide.shtml
Related
I'm in the process of updating a website I made almost 2 years ago. It was my first real website and I made some mistakes (some more serious that others).
What apparently is one of my biggest is making database calls from the view.
I'm pretty damn sure there is a better way to do this:
Use Case:
Someone fills out a form for a new subject, populating the Subject table, and they have been marked "enrolled", Subject.enrolled = 1
Based on that, I now need to create a record in 5 other tables (such as Baseline)
Downhill from here, here is my method
Determine if the record exist based on subject_id from Subject (sub)
<$ if Baseline.where(subject_id: sub.subject_id).first != nil $>
If it does not exist, create the record, (otherwise display the link)
<%= Baseline.create(subject_id: sub.subject_id) %>
This all happens in the view, and creates a front-end table with links to each record in the process. So I'm creating records based on for-loop logic...
Question:
So I'm looking for direction. I don't want to guess how to do this - I'm pretty sure the model/controller should do this - I want to learn how to do it correctly. How do I create records automatically, based on a value in a table?
Thank you for your time.
Not quite sure how your domain and code looks like, but to answer this question: 'How do I create records automatically, based on a value in a table?', it seems that you could use ActiveRecord callbacks, like this:
class Subject < ActiveRecord::Base
after_commit :create_baseline_if_enrolled, on: [:create, :update]
private
def create_baseline_if_enrolled
return unless enrolled?
# enrolled? == true, you may create these models here
end
end
To answer your question:
It depends :) This is just one possible solution. Another one would be to put such a custom logic in your SubjectsController and call it directly from the #create, #update methods. Both approaches have pros and cons. For example, abusing callbacks (anywhere) makes code less readable and harder to debug. On the other hand, putting such logic in controllers puts a burden on you that you have to remember about calling it if you happen to be editing subjects in other places (but is more explicit). Whichever way you choose, remember not to make your classes too fat, for example try to use service object pattern to separate such custom logic as soon as you feel like it is getting out of hand. :) And don't forget about tests - when things go wrong, tests make refactoring easier.
Consider I have a controller with an action which renders a view. The view needs data to render. I know the following ways to prepare and send it to the view:
Using instance variables
class CitiesController < ApplicationController
def index
#cities = Cities.order(:name).limit(10)
end
end
This is the default approach which can be found in Rails documentation, but it has some disadvantages:
It makes the action code fat which becomes responsible not only for controller logic, but also for the data preparation.
Views need to access this data through instance variables – those #-variables break the principle of least astonishment.
Using helper methods
class CitiesController < ApplicationController
helper_method :cities
def index
end
def cities
#cities ||= Cities.order(:name).limit(10)
end
end
That's the way I prefer the most. It keeps action methods clean, so I may implement controller logic there not mixing it with data preparations in one method. Also, there's no need to use mysterious instance variables in views, making them isolated. However:
The data preparations are still in the controller. It becomes unreadable when there are a lot of these helper methods, especially when they are relative to different actions/views.
There's a need of having a unique name for each helper method. Say, I can't have a method called products which will return different data for different actions (of course, I can do it in one method, but it would look ugly).
Using the facade pattern
Partially the problem is solved in this article: https://medium.com/p/d65b86cdb5b1
But I didn't like this approach because it introduces a #magic_facade_object in views.
Using inherited resources
It may look beautiful in examples, but in my opinion when it comes to the real code, controller code becomes a spaghetti-monster very fast. The other thing is that a page view usually needs not only the resource but also other data to render (sidebar blocks, etc.) and I still have to use another way to prepare it. Combining different approaches makes the code even more unreadable. Finally, I don't like to use resource variable, because it makes not very clear what is the view about.
So, here is the question. How do you keep your controllers clean?
How do you keep your controllers clean?
By writing DRY code and sprinkling some gem magic around.
Having a look at your bullet points, I think I have a different opinion on most of the stuff.
#cities = Cities.order(:name).limit(10) is exactly what i think belongs into a rails controller and it does not violate the principle of least surprise, it's kind of the opposite. instance variables are the default way of passing around variables from controllers to views, even though that is a pretty ugly thing to do. it's "the rails way" (TM)!
decent_exposure takes away most of these concerns
please stop applying old-school pattern to rails or ruby code. it's really just useful in large applications where you are struggling to keep sane with the amount of code that's within a single controller method. write clean code, test it thoroughly and you will be fine 80% of the time.
don't use "one size fits all" tools. most often, you need to write more configuration than you would need code to make it work. it's also getting a lot more complex through this kind of things.
I have an application in Ruby on Rails with mvc framework. As of now, I have API calls in the controller but don't think this is the right place for them. What kind of file should all my API calls go in? Thanks
def getDetails(id)
api_response = HTTParty.get(base_uri, :query => {:DID => id, :DeveloperKey => devKey})
#json_hash = api_response.parsed_response
return #json_hash
end
API calls to external services (3rd party) are not specific to your app, as their service is available to everyone (in theory). It is my understanding that these sorts of features go in the lib/ directory because they are not app specific. Ideally you could then pull out the code from your lib in your project, and drop it into someone else's lib/ in another project and it would still work just fine.
Put the call in the lib/. If you want, you can create the a model from the returned data in your controller.
It would look something like this:
app/controller/
class YourController < ApplicationController
def getDetails
# keep in mind, api call may fail so you may want surround this with a begin/rescue
api_response = YourApiCall.new.get_details(params[:id])
# perhaps create a model
#model = SomeModel.new(fname: api_response[:first_name], lname: api_response[:last_name])
# etc...
end
end
lib/
require 'HTTParty'
Class YourApiCall
def get_details(id)
HTTParty.get(base_uri, :query => {:DID => id, :DeveloperKey => devKey})
#json_hash = api_response.parsed_response
return #json_hash
end
end
Very late to this one, but thought I'd add my 2p/2c.
I like to try to keep my controllers clean of anything apart from controller code, which I loosely define as program flow code based on request type and parameters. For example, choosing the correct template for the request type or choosing the correct method to call based on whether a user is logged in or not.
When it comes to calculating the responses, I don't like to litter the controller with lots of code that manipulates models and sets instance parameters. This is hard to test and even harder to re-use. I prefer to defer to another object and return a single value object to the template.
Sometimes I can defer to a model: maybe it's a simple look-up and I'm just sending a single model to the template, or an array of models.
Maybe I've implemented a useful method in a model to return an appropriate value or value object.
However sometimes I'm doing something that doesn't use a model, or that uses a several models, or that doesn't feel like it should actually be cluttering up the model. In this case, neither the controller nor a model is an appropriate place for the code.
The lib directory doesn't feel right either. I tend to treat the lib directory as somewhere that contains code that I haven't been bothered to turn into gems yet. If the code I'm writing only makes sense in the context of the application, it doesn't sit well.
So I turn to service objects. Under the 'app' folder I have a 'services' folder, which contains small, functional classes that encapsulate single chunks of site behaviour. (Or sometimes, coordinate several other services to provide a simple interface for the controller.)
This allows me to slim down my controllers AND my models, and makes a perfect place to put code that needs to contact an API.
If you wanted to go one step further you could wrap the API itself in a wrapper class (or set of classes) and keep those in the lib directory (for conversion to a gem at a later date perhaps). Then the service object would perform the task of calling the API wrapper with the appropriate values (passed from the controller) and responding with something that a template can interrogate cleanly.
Of course, you can go further than this and add more layers. A presentation layer, for example, could sit between the service object (providing generic values) and format data for a specific view. (Maybe you want to provide both a web page and an RSS feed and they need different date formats for example.)
But you get the idea.
By my coding style (and understanding of MVC), external calls would be placed in a "tableless" model. RailsCasts 193 talks a bit about this concept, and a less clunky syntax is supported in Rails 4. If you need to have any manipulation of the code, the model seems like the logical place to place these. Moving those methods into the controller would work, but could create problems as your app grows.
Another consideration with external API calls is actually storing those in a database, which would should definitely be in a model at that point, so (to me) it becomes clearer that these really should be in the model.
I need to have two (or maybe even more) different create (and update) methods in one controller. I already have views displaying the forms, so I basicaly only need to tell the submit which method to call in the controller. Is that possible? If so, how? Or can I only have one create method and have that method do different things depending on which view called the method?
Thanks
Ignoring the fact that this sounds like a really terrible idea, it's possible. You will need to add some more routes that will match the new actions in your controller. You won't be able to call them 'create' and 'update' because method names must be unique within the same class.
Having said that, I really beg you to rethink your approach. REST, as described in the Rails Getting Started guide, by far the standard for building Rails applications. If you're not familiar with it, I would recommend stopping where you are and reading up on it. Your application will be much easier to build and maintain, and you won't waste time asking structural questions. If you are familiar with it and are choosing to ignore it, then I wish you the best of luck.
you can use this command:
rails g scaffold_controller 'controller_name'
or if spastic method you can use this:
rails generate controller 'controller_name' add new
Let's say that you have an object Book. You can change values of Book in any method inside of your books_controller.rb as long as that method has access to #book.id.
def crazy_create_method
book.create (book_params)
book.save
end
That being said, try to stick to the default new/create methods and if you need to get weird later on it's always easy to call the code belong in whatever method you need. Rails bakes a lot of out of the box functionality into the default REST actions.
book.title = my_title
book.save
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.