I'm learning Rails. I have a controller responsible for presenting data from parsing files uploaded by the user. I don't want the data to be stored anywhere in the model. Can I include a class that I can instantiate in my controller method? Here is a basic code example of what I mean:
This controller only contains one method:
class MyController < ApplicationController
def index
test = FileProcessorService.new
#test = test.test()
end
end
Here is the class that will handle the logic when the instantiates calls its method:
class FileProcessorService
def test
return 'This is a test'
end
end
My questions:
Where is the best place to store this class? How can I refer to this class in my controller?
Any advice on this particular topic of using classes in rails? Are instances of a regular ruby class a problem in the controller? I dont want my users seeing the same data. Thats why I dont want to include global variables in my controller. No models since I have an MVC back ground with Java MVC. I'll move on to models once I understand how the basic rails controller functionality works.
Thank you in advance for your help.
I usually put these in app/classes, or if there are a lot of them, into more specific folders likes app/services, app/notifiers, etc.
You can enable autoloading in config/application.rb:
config.autoload_paths += %W(#{config.root}/app/classes #{config.root}/app/services)
If they're not application-specific, extract them to a gem.
Related
I'm a bit confused on what's the proper design for a page that doesn't actually need a model.
As an example, I want to create an export page that will allow a user to export various other models into a CSV.
Obviously I'll need a view (most likely a show.html.erb file), and a controller; but making some sort of Export model wouldn't really make sense, and the same goes for creating new/edit/index views.
Is the correct way to do this just to manually create the view + controller for my Export page? It seems weird to not have a model after reading the rails documentation which is so heavily based on the MVC pattern, but I also don't see any reason why I "need" to follow the pattern for a case like this where a model just wouldn't make sense.
My guess is you are using the scaffold generator which does create a model.
If you just want to create the views and the controller type this in your terminal.
rails g controller exports
This will create the views, controller, and assets associated with the controller. Just add the routes.
resources :exports
You don't need a model. The generators and assumptions in rails generally work better if you have a model, but you don't need one. You can manually create the controllers and views, or use rails g controller exports.
You might look into form objects to provide a model in the controller - those are plain old ruby objects that provide a model without a database record.
A form object for an Export might start like this:
class Export
include ActiveModel::Model
include ActiveModel::Validations::Callbacks
end
Create a controller in your app/controllers folder like this:
class ExportsController < ApplicationController
def show
#export = ... # Your query here
end
end
Create a folder named exports inside app/views folder.
Create your show.html.erb inside the exports folder you just created.
Add manually your exports#show route like this:
resources "exports", only: [:show]
You should be good to go. Add the necessary auth and before_action methods in your ExportsController.
In my web application I have a model User. It's quite common that you need to select some users for many different purposes related to many different models. My aim is to make this component very easy and fast to attach in a new place. E.g. if a users wants to select his friends the result of selection should be handled by User controller, but if you want to assign some users to a task this should be handled by Task controller.
Do you have any concept how to do this? Should I make another controller for selecting? How should I pass the selection to the suitable controller? Maybe by session? Do you have any other suggestions?
I think what you are looking for is a module which has common methods. If so you can do something like:
Create a module called Users and add the methods to that, and keep it inside your lib folder
Ex:
<app root>/lib
module User
def friends
<returns the given users friends>
end
end
and then you can call this module in both your controllers and models
Ex:
Class Friend
include User
end
Class FriendsController < ApplicationController
include User
end
I have a view helper file, app/helpers/analysis_helper.rb, whose toplevel methods I've been using in various view files. Works fine. I then defined an AnalysisSummary class inside analysis_helper.rb to package up some view-specific functionality.
However, when I try to instantiate an AnalysisSummary in a view file, I get the error:
uninitialized constant ActionView::CompiledTemplates::AnalysisSummary
Perhaps Rails is telling me that I shouldn't be defining a class inside a helper file? If so, where would you suggest parking AnalysisSummary? It's not a controller, it's not a model...
Thanks.
In Railscasts #213 (Revised) (subscribers only link, alas), Ryan Bates provides an example of how (and why) you might include a class within a helper. The basic gist is this:
# app/helpers/calendar_helper.rb
module CalendarHelper
def calendar(date = Date.today)
Calendar.new(self, date).render
end
class Calendar
def render
# Calendar, render thyself
end
# ... additional methods called by #render
end
end
To those opposed to classes within helpers, what do you make of Ryan's choice? Helpers are for generating markup, right? So if all the logic within class pertains to rendering (rather complicated) HTML, I would think that what it does (as opposed to what it is) makes it appropriate for inclusion in a helper.
Why does it need to be a class? Why not just a collection of methods? That's what a helper is: a collection of helpful methods. Business logic does not belong in helpers. You can place your code in a module within the helper file if you want to give some more structure and organization, though.
You can put classes in app/models without it having to be an ActiveRecord class, but you should seriously consider what the purpose of your class is before you place it there.
If it concerns only rendering the view, and not accessing data directly, it belongs in the view or a view helper.
You can call the class by explicitely mentioning the helper name
ApplicationHelper::AnalysisSummary.new
But I dont think it is a good idea to have classes in helpers.
It's a module then :) Definately do not define classes inside helpers. Jsut use a simple module to do the job.
It looks like you cannot use a helper in a controller even if both of them belong to the same class. For example: XYZHelper and XYZController...
I was under the impression that if the prefix is the same "XYZ" then the method in the helper can be used in the controller and in the view, but I think this is not the case.
So how do I remove some common functionality from a controller and place it in a helper. I want to place that piece of code in a helper because other controllers may be using it. What is the best way to approach this.
Thanks,
Jai.
There are a few ways you could share some code between controllers:
Application controller: If the code in question is an action/method which ought to be in a controller, but could be used by several controllers (or all of them), then this might be a place to put it.
the 'lib' directory. just a general purpose place to put code which should be shared.
Put it in the model. This may or may not be applicable, but its worth taking a good look at the code you're trying to move and thinking about whether it is something which makes sense on a model (instead of a controller or random class/module in lib).
Follow Pete's guidelines. If you still need to expose the methods then do the following:
Add the methods to ApplicationController class and register the methods as helper methods by calling helper_method.
class ApplicationController < ActionController::Base
helper_method :foo, :bar
private
def foo
"foo"
end
def bar
"bar"
end
end
I want to share code not related to views between several controllers in my Rails app. Where in the directory structure should I place it?
EDIT: the code in question if something all controllers use to determine how they render the model data
If the code is something like modules with utility methods in these could be placed in the lib folder. Alternatively you could create a common superclass for some of your controllers if they share behaviour.
Please post an example of the kind of code you're thinking of.
If it's "something all controllers use", I would place it in a base class used by all controllers. The "application_controller" comes to mind.
I have been creating modules in lib to provide code to other classes.
Here's an abbreviated example module that defines values for views that can be instantiated from different controllers.
module ControllerDefaultValues
def default_value_for_some_controller()
#controller_name = "some_controller"
end
end
To use this, simply include the module in your class:
class SearchesController
include ControllerDefaultValues
#
def search_some_controller
default_value_for_some_controller()
render(:partial => "search_results")
end
end
The main benefit of this method is it keeps your controllers directory focused on controllers and your models directory focused on logic.
Personally i think its fine, if its controller related to put it in your controllers directory, but, labelled as a module, e.g. app/controllers/what_am_i_module.rb since it is specific to the application in development.
lib seems like a place to me where i would put framework/core enhancements or monkey patches which are non-specific to the application.
If it's going to be used by all your controllers, stick it in application_controller.rb
All your controllers inherit from ApplicationController, so they'll all have access to them.