Programmatically Create Controller in Rails - ruby-on-rails

What's the best way to dynamically create a controller in Rails.
I've got a class that needs to generate a bunch of controller that inherit from it. I could just create a bunch of files in /app/controllers, but they'd all be basically empty files. There's got to be a way to generate these classes dynamically and have them treated like other controllers in Rails, e.g. reloaded correctly in dev mode.
I tried putting this in a config/initializer:
FL.contact_types.each do |contact_type|
controller_name = "#{contact_type.pluralize}Controller"
Object.const_set(controller_name.to_sym, Class.new(ContactsController)) unless Object.const_defined?(controller_name.to_sym)
end
This worked, but I run into the dependency/reload problem and get “A copy of AuthenticatedSystem has been removed from the module tree but is still active” since the ContactsController inherits from ApplicationController which includes AuthenticatedSystem.
Is creating a bunch of empty files really the best solution?

Are you sure you need multiple controllers? Can you have a single controller that gets passed a value to indicate how it behaves? You could also make a module that has the common functionality in it, and have the empty controller files that only reference the module.
a route could be used to pass the type in:
map.route "/:type_of_contact/:action/:id/, {:controller => :contact_type}
now in all the actions, in params you have the key :type_of_contact to guide your system.
You'll want to make sure this is near the end of your routes so it doesn't override access to your other controllers.

Related

Creating a rails view + controller that doesn't require a model?

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.

Creating Methods to an existing Controller via Terminal

I have an existing model that I'd like to add a number of methods to. While I could manually add the methods to the controller as well as its corresponding style/script templates and routes I'd much rather have them done just as I would've when I created the controller in the first place:
rails generate ControllerName hello goodbye
Is there any way to accomplish this?
I think this is a perfectly valid thing to want to do. However the general concensus seems to be that it is too trivial hence why there is no option for it.
A couple of things you could do though:
If you are only adding one or two actions to an otherwise complex controller you could generate another dummy controller with just those two actions. Then copy over the new bits to your existing controller and trash the dummy one. Something like git is great for keeping a track on what the generator changed here.
Alternatively if you want to add a lot of new actions to a trivial controller you could save off the original files, let the generator overwrite the existing controller and then put back the original bits.
Remember you can always use the --pretend option on the generator to see what it would create without actually doing it. This can be useful especially to see what view files it would create for the actions in your case.
You can do
rails generate controller mycontroller hello goodbye
This would generate controller called mycontroller with methods hello and goodbye.

How to share an array between two classes that inherit from different classes

I've got a Rails application with a PubSub Server (Faye) as middleware.. I've got the usual Rails-structure for Models, Views and Controllers, and I've got some controllers for my Socket-channels.. (Provided by FayeRails)
The problem:
I need to share a client list between my socket controllers and my general controllers.
This is because the authentication is done via a Rails controller (so I'm able to use sessions)..
Normally I would put this kind of stuff in my ApplicationController so all inherited controllers and views can get to it, but the socket controllers are inherited from FayeRails::Controller so that not an option.. I have no clue where the instances of these controllers go.. Also, I can't edit the initialize because all the controllers are setup automatically by Rails and the FayeRails gem. I tried using globals, but that feels wrong.. Also I've been thinking of ActiveRecord, but it doesn't feel right to add fast-changing data to a database.. Lastly I though of an ActiveRecord-like class that holds the list, but this feels the same as a global..
I can't really think of any other options to share the client list between these two controllers..
What would be a nice and clean way for doing this?
You could put what you need in a module in the lib directory. The include it in your application_controller and then extend the main FayeRails controllers, include the module in there as well. To extend, just created a new one with the same name in your controller file, maybe sure the class name is the same, then require it in your config/initializers/extensions.rb file.
Example
# config/initializers/extensions.rb
require "#{Rails.root}/app/controllers/whatever_controller.rb"
As for speed, yeah, if you're worried about that I would look into keeping what you need in a persistent redis DB. But if FayesRails uses ActiveRecord methods I'm not sure how easy/hard that would be.

Custom Controller variable in application.html

User Story:
Action for Facebook that has open graph object.
For this I need to modify the tag defined in application.html
Problem:
The logic would need to be defined in helpers or the application_controller
From my understanding this is not clean.
Question:
I want to pass variables directly into the application.html view.
Preferably pass those variables from a custom controller into the application.html. This way I can still utilize the rails routing system to only pass those variables when I am on the facebook action.
The common mechanism for passing variables in to the view is to create instance variables in your controller as these are ported over automatically.
This is the standard approach if it is almost certain they will be used. For things that may not be used, create a helper method that will take care of providing them.
This is the difference between doing this:
def show
#facebook_graph = ...
end
And this in a helper:
def facebook_graph
...
end

Where to place Rails code that is not a model, view, controller or helper?

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.

Resources