I'm refactoring my companies routes file following this SO post to look like the following.
config/application.rb
module YourProject
class Application < Rails::Application
config.autoload_paths += %W(#{config.root}/config/routes)
end
end
config/routes/admin_routes.rb
module AdminRoutes
def self.extended(router)
router.instance_exec do
namespace :admin do
resources :articles
root to: "dashboard#index"
end
end
end
end
config/routes.rb
Rails.application.routes.draw do
extend AdminRoutes
end
However much of our newer RoR code we put into appsules, which are self contained little pieces of the application that contain their own controllers, models, serializers, etc, and someone mentioned how nice it would be if they also contained their own routes. The path to that would look like the following
/appsules/#{appsule_name}/routes.rb
But when I look at the config.paths in my application.rb I don't see any paths pertaining to the appsules directory. Is this possible to read in routes files in that fashion?
Are you updating the autoload path to use the new folder structures? Something like:
module YourProject
class Application < Rails::Application
config.autoload_paths += %W(
#{config.root}/config/routes
#{config.root}/appsules/appsule1_name/routes.rb
#{config.root}/appsules/appsule2_name/routes.rb
)
end
end
If you want them added dynamically, you should be able to iterate the appsule directory and add these files dynamically to the autoload path.
Related
I have a namespaced Post controller as below
class Admin::Blog::PostsController < Admin::BaseController
end
and a namespaced model as follows.
class Blog::Post < ActiveRecord::Base
end
But when I try to access the model inside the index action of the post controller as below
def index
#posts = Blog::Post.where(:foo_id => params[:id]).paginate(:page => params[:page], :per_page => 20)
end
I get the following error
LoadError at /admin/blog/posts
Expected/app/models/blog/post.rb to define Post
But when I move the model to Admin::Blog::Post namespace from Blog::Post is works.
I'm bit confused with this and not able to get what is going on with this.
Is it required that Controller and Model should be present in the same namespace ?
Following is the snippet from routes.rb
namespace :admin do
namespace :blog do
resources :posts
resources :categories
end
end
Blog module snippet
module Blog
def self.table_name_prefix
'blog_'
end
end
Preloading controllers and models
config.autoload_paths += Dir["#{Rails.root}/app/models/**/**"]
config.autoload_paths += Dir["#{Rails.root}/app/controllers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/helpers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/tags/**/**"]
config.autoload_paths += %W[ #{Rails.root}/app/extensions #{Rails.root}/app/modules #{Rails.root}/app/drops #{Rails.root}/app/filters #{Rails.root}/app/mailers ]
This is probably caused by rails' autoloader. When doing this :
module Foo
class Bar
end
end
And then trying to use Foo::Bar, the autoloader first tries to locate app/models/foo/bar.rb. The file is loaded, and module Foo is defined here (albeit as a module containing solely Bar) so the autoloader never attempts to load app/models/foo.rb.
This should only happen in development mode, as in production mode all of your files are require'd on startup.
There are two workarounds AFAIK :
Require the module
using require_dependency :
require_dependency 'foo'
module Foo
class Bar
end
end
This is IMHO the right solution, as it does not break the constant lookup, but it is also a bit annoying as you have to add the require statement on top of each namespaced file.
Create Custom Active record Base
This solution doesn't rely on autoloading. Set the models to inherit from the following, instead of from ActiveRecord::Base directly:
class CustomActiveRecordBase < ActiveRecord::Base
self.abstract_class = true
# If no table name prefix has been defined, include the namespace/module as
# table name prefix, e.g., Blog:: -> blog_
def self.table_name
# If a table_name_prefix has been defined, follow default behaviour
return super if full_table_name_prefix.present?
# Find the prefix, e.g., Blog::Post -> 'blog', User -> ''
prefix = model_name.name.deconstantize.underscore
# If no prefix, follow default behaviour
return super unless prefix.present?
# Otherwise add the prefix with an underscore
"#{prefix}_#{super}"
end
end
Then there is no need to define self.table_name_prefix in blog.rb.
This could all be done by monkey-patching ActiveRecord::Base, but this interferes with other classes, such as ActiveRecord::SchemaMigration, which doesn't have a table prefix.
Note :
This bug seems to have been resolved in rails 4. I used the second workaround a lot while on rails 3, but I've tried to reproduce the bug in rails 4 and it does not show up anymore. I think they modified the way the autoloader works... For more info, see the rails guides on autoloading and reloading constants
I am very new to Rails, and am trying to learn how the /lib/ directory in Rails works - and how to reference variables defined in the /lib/ directory for use in a view.
I have a file called helloworld.rb and it's saved in the /lib/ directory in Rails.
The helloworld.rb file has the following code:
module HelloWorld
def hello
#howdy = "Hello World!"
end
end
I want to be able to display the results of this method on a view called index.html.erb, so I include the following code in the index_helper.rb file:
module IndexHelper
require 'helloworld'
end
Also, I include the following code on the view index.html.erb:
<%= #howdy %>
What am I missing?
You need to call Helloworld::hello in order for it to create your instance variable.
maybe you could put it in a before_filter in your controller
require 'helloworld'
class FooController < Application::Controller
before_filter :setup_hello , [:only=>:create, :edit ]
def create
# whatever
end
def edit
#whatever
end
def setup_hello
HelloWorld::hello
end
end
So now, every time you either your edit or create action, 'setup_hello' is executed, which calls the hello method in your module, and sets the #hello instance variable.
You should any of these lines to config/application.rb file.
module [App name]
class Application < Rails::Application
# Dir.glob("./lib/*.rb").each { |file| require file }
# config.autoload_paths += %W(#{Rails.root}/lib)
end
end
Uncomment any of commented lines. Both of them do same work.
Dir.glob finds all .rb files in app and require each file in rails app.
Also config.autoload_paths also load all files in lib folder.
You have to add the lib folder to the auto-load path in config/application.rb
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/lib)
I'm trying to extract a portion of my Rails project into my lib directory but I can't work out how to link my files up correctly. My directory structure looks like this:
lib/
eventable/
calendar.rb
helpers.rb
# Rest of rails directories/files
I'm requiring the eventable directory in config/application.rb:
config.autoload_paths += %W(#{config.root}/lib #{config.root}/lib/eventable)
My helpers and calendar rb files:
# helpers.rb
module Eventable
module Helpers
def calendar_for...
Calendar.new...
end
end
end
# calendar.rb
module Eventable
class Calendar
# methods defined here
end
end
I'm then mixing my Eventable::Helpers module in the regular Rails helpers so that I can use calendar_for in my views:
ActionView::Base.send :include, Eventable::Helpers
This last step seems to work fine. However, when I go to a view which is using this helper I get:
uninitialized constant Eventable::Helpers::Calendar
If I change my helper so that it tries to access Eventable::Calendar.new instead then I get:
uninitialized constant Eventable::Calendar
When I had all of these in a single file, it all worked perfectly. So how I can correctly link these files up?
It looks like you need a loader-type file to tell Rails where to find code for the Eventable module.
Try add a lib/eventable.rb with:
module Eventable
autoload :Calendar, 'eventable/calendar'
autoload :Helpers, 'eventable/helpers'
end
You shouldn't need to change your load path if you have the loader file in place.
I had a similar problem. I solved it by changing the way modules are required.
In application.rb
config.autoload_paths += Dir["#{config.root}/lib/"]
Create /lib/eventable.rb with the following code
require "eventable/helpers"
require "eventable/calendar"
I am developing a rubygem specifically for Rails applications and I want to add a controller from my gem so that it will be available on the Rails app(Similar to what devise does with RegistrationsController, SessionsController).
On the gem side:
I've tried adding the following
app/controllers/samples_controller.rb
class SamplesController < ApplicationController
def index
.
.
end
end
And then on my rails routes add it either as:
match 'route' => 'samples#index'
or
resources :samples
Clearly I got something wrong over there but I have no idea what is it? Do I need to explicitly require my SampleController somewhere or an initializer on the app?
Right now I am getting this error when accessing the route
uninitialized constant SamplesController
Thanks :)
Let's assume your gem is called MyGem and you have a controller called SamplesController that you want to use in the app. Your controller should be defined as:
module MyGem
class SamplesController < ApplicationController
def whatever
...
end
end
end
and in your gem directory it should live at app/controllers/my_gem/samples_controller.rb (not under the lib folder).
Then create engine.rb in your gems lib/my_gem folder with code
module MyGem
class Engine < Rails::Engine; end
end
You can write routes inside your gem by writing creating routes.rb in config folder with code
# my_gem/config/routes.rb
Rails.application.routes.draw do
match 'route' => 'my_gem/samples#index'
end
Final structure something like this
## DIRECTORY STRUCTURE
#
- my_gem/
- app/
- controllers/
- my_gem/
+ samples_controller.rb
- config/
+ routes.rb
- lib/
- my_gem.rb
- my_gem/
+ engine.rb
+ version.rb
+ my_gem.gemspec
+ Gemfile
+ Gemfile.lock
Thats it.
First of all you have a typo in your code: AppicationController should be ApplicationController.
Then, you're not following the Rails naming conventions (plural for resources etc.):
In your routes it would have to be either resources :samples or resource :sample.
Your controller class should be class SamplesController and
the filename of the controller should be samples_controller.rb.
Follow the conventions and you should be fine.
to set up your route, create a routes.rb file in the config directory of your project. To have it match on the sample route, do the following:
config/routes.rb
Rails.application.routes.draw do
<resource definition here>
end
app/controllers/samples_controller.rb
module Samples
class SamplesController < ApplicationController
def index
.
.
end
end
end
Remember to include the module in the application controller
include 'samples'
Have you looked at this site:
http://coding.smashingmagazine.com/2011/06/23/a-guide-to-starting-your-own-rails-engine-gem/
I have a class that I'm trying to use in my controller in the index action.
To simplify it, it looks like this
class PagesController < ApplicationController
def index
#front_page = FrontPage.new
end
end
FrontPage is a class that I have defined. To include it, I have placed it in the /lib/ folder. I've attempted to require 'FrontPage', require 'FrontPage.rb', require 'front_page', and each of those with the path prepended, eg require_relative '../../lib/FrontPage.rb'
I keep getting one of the following messages: cannot load such file -- /Users/josh/src/ruby/rails/HNReader/lib/front_page or
uninitialized constant PagesController::FrontPage
Where do I put this file/how do I include it into a controller so that I can instantiate an object?
This is Rails 3.1.3, Ruby 1.9.2, OS X Lion
You should be able to use require 'front_page' if you are placing front_page.rb somewhere in your load path. I.e.: this should work:
require 'front_page'
class PagesController < ApplicationController
def index
#front_page = FrontPage.new
end
end
To check your load path, try this:
$ rails console
ree-1.8.7-2011.03 :001 > puts $:
/Users/scottwb/src/my_app/lib
/Users/scottwb/src/my_app/vendor
/Users/scottwb/src/my_app/app/controllers
/Users/scottwb/src/my_app/app/helpers
/Users/scottwb/src/my_app/app/mailers
/Users/scottwb/src/my_app/app/models
/Users/scottwb/src/my_app/app/stylesheets
# ...truncated...
You can see in this example, the first line is the project's lib directory, which is where you said your front_page.rb lives.
Another thing you can do is add this in your config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
That should make it so you don't even need the require; instead Rails will autoload it then (and everything else in your lib dir, so be careful).
The file was named FrontPage.rb. Changing the name to 'front_page.rb', but leaving the class name as 'FrontPage' resolved the issue.
We just need to load the file,
class PagesController < ApplicationController
require 'front_page.rb'
def index
#front_page = FrontPage.new
end
end
lib/front_page.rb
class FrontPage
end
We can also set the application.rb to autoload these files
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Second option would be a preferable solution.