Same controller name in two different directories - ruby-on-rails

From 'Agile Web Development with Rails 4' pag.272.
If an incoming request has
a controller named (say) admin/book, Rails will look for the controller called
book_controller in the directory app/controllers/admin. That is, the final part of the
controller name will always resolve to a file called name_controller.rb, and any
leading path information will be used to navigate through subdirectories,
starting in the app/controllers directory.
Imagine that our program has two such groups of controllers (say, admin/xxx
and content/xxx) and that both groups define a book controller. There’d be a
file called book_controller.rb in both the admin and content subdirectories of
app/controllers. Both of these controller files would define a class named BookController. If Rails took no further steps, these two classes would clash.
To deal with this, Rails assumes that controllers in subdirectories of the
directory app/controllers are in Ruby modules named after the subdirectory.
My question is: how could the two book_controller.rb files clash?
I have two different URLs: ..../admin/book and ..../content/book, how can they clash? In the previous paragraph it explicit says
[..] any leading path information will be used to navigate through subdirectories, starting in the app/controllers directory

The file names do not matter. What matter are the constant names.
It's totally okay to have two files with identical names, like controllers/admin/books_controller.rb, and controllers/books_controller.rb.
However, the class names inside those controller should be different. You can add namespace to differentiate them. For example
class Admin::BooksController
class BooksController

Imagine the filepaths like this
../app/controllers/admin/book_controller.rb
&&
../app/controllers/content/book_controller.rb
Rails uses convention over configuration: http://en.wikipedia.org/wiki/Convention_over_configuration
Like it states in the last paragraph
If Rails took no further steps, these two classes would clash. To deal
with this, Rails assumes that controllers in subdirectories of the
directory app/controllers are in Ruby modules named after the
subdirectory.
Someone please correct me if I'm wrong but rails would look for models named admin.rb and content.rb

Related

Rails: ruby class name must base on file name?

I'm learning rails 5.0. When I learn Ruby, I know that ruby file name can be different with class name inside. But when I move to rails, I see that ruby file name and class name must have same format. For example, a class name CheckInDetail will be in check_in_detail.ruby. I also see that the module name must be matched with directory name. For example, module authentication must be inside authentication directory. Some example for my conclusion is:
rspec: class name must base on file name.
grape: class name must base on file name. Also module name must be matched with directory.
If I don't follow those convention, when compiling rails will throw exception. I don't see those conventions on those library github pages. Will this true for whole rail project, with all libraries ?
With rails there is a convention how you should define classes and file names. A class named ManageOrder should reside inside a file named manage_order.rb. This is a standard convention that rails follows otherwise rails won't be able to load the class.

How add new folder with class in rails app?

I have 2 questions in rails app context:
I have some classes which aren't "modele", but require in my sytem, so I want separe them
1) How can I add "class' folder in app/? (if I create it and put classes, their are no included)
2) how can I put folder "model" in "app/class" folder (same thing here, the model are not included if I move it)
thx.
It´s kind of unclear what you are asking.
But if you want to autoload additional directories you can do it by placing something like this in config/application.rb
config.autoload_paths << Rails.root.join('app/class')
But please don´t call your directory class, use something descriptive instead.
By convention code that does not fit inside models, controllers, views, helpers or concerns and placed in the lib directory at the project root.
Edit:
You can load subdirectories by using a glob:
config.autoload_paths << Rails.root.join('app/classes/**/')
For quite some time Rails has autoloaded all paths under /app, as mentioned here
You may have run into a problem when using a "app/class" directory since "class" is a reserved word and "Class" is a class in Ruby.
There is a problem with your example:
exemple: "app/classes/effects/attribute.rb" with "class Effect::Attribute"
Notice that in the file path "effects" has an "s" at the end, whereas your module name does not "Effect::Atttribute". Those should match. Either both end with "s" or not, and when they do match Rails autoloading should work.
You should remove any of the other suggestions about appending to config.autoload_paths.

Autoloading Rails models that don't follow the default file name structure

THE SHORT VERSION: How do I tell Rails to autoload an ActiveRecord class called ClassName that isn't located in the default location (app/models/class_name.rb). E.g. what if it's in app/models/subdirectory/class_name.rb and I don't want to rename the class to Subdirectory::ClassName?
THE LONGER VERSION:
I know that, by default in Rails, my class names have to follow a specific structure for Rails to be able to autoload them.
E.g. If my class is called Person, if I put it in app/models/person.rb, Rails can load it fine, but if I put it in e.g. app/models/person_class.rb, it can't. If I namespace it, e.g. Humanity::Person, I need to put it in the right folder app/model/humanity/person.
(Plus I can put classes in lib but I'll leave aside that detail for now)
So far so good. But what happens when I have a ton of ActiveRecord classes clogging up my app/models folder and I want to logically organise them into directory, but don't want to rename or namespace the actual classes? How can I tell Rails to autoload this classes?
Or is there a good reason why I shouldn't do this?
Add this line to config/application.rb
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**/}')]
Then you can use your model with their name as it is without name-spacing.

what is the correct way to add classes to a controller in rails?

If i need to add (project specific) classes to my controler in rails, what is the correct way/place to put and "include" them/there .rb files? (quotes for: not the ruby keyword include)
I am new to rails, and did not find the correct way. LIB sounds like for more public libraries and - what I have learned - is not reloaded per default in dev mode.
sure, I could put all in controler.rb, but ...
the anser for me:
First: there are no rules, if you keep in mind (or learn like me) the rails rules:
NameOfCla -> name_of_cla(.rb) <-- not using class as word for clearence
name your class how you like:
class ExtendCon #<--- not using controller here for clearence
....
put it in a file extend_con.rb, wait for the path explaination, please. if you named your class 'MYGreatThing' it will be 'm_y_great_thing' (never testet that), so avoid chineese charachters
if your controller uses
#letssee=ExtendCon.new
rails learns that class and file (extend_con) on its own. i still did not figure out if a server restart is needed. (the first time)
choose the path to put the file: (I preferre Daves way) app/myexten or what you like, making it 'app' specific and still distquishes to standard rails 'things'
if you are not lasy like me (i put it in app/ontrollers)
put the path you have choosen into
config/application.rb like (comments are there to find it)
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/app/controllers)
config.autoload_paths += %W(#{config.root}/app/myexten)
this one workes for me in all modes including "developer" and i did not need to put "my own" things in app/lib
It depends.
I tend to put library code used explicitly (e.g., instantiated, injected, etc. into app-level artifacts) into app/xxx where xxx signifies the "type" of thing, like decorators, services, etc.
Magic stuff tends to end up in lib, like monkey patches, architectural-level artifacts, and so on.
Code anywhere can be added to the autoload paths, required automatically by an initializer, etc.
Rails 4 comes with an internal directory for controllers called concerns. You could try using that.
app/controlls/concerns
If you have concerns/foo_bar.rb, you include it as follows:
class FooController < ApplicationController
include FooBar
end
Models also have their own concerns directory. I find this approach useful, and it can be applied to Rails 3. You just have to add the directories to your load paths.

Autoloading from namespace inside a custom folder in app

We're currently developing a custom cms engine for ROR 3.2. In this process several class types originated that we want to be first class citizens in our rails application, meaning they should reside under the app folder of the application and it's plugins.
Currently we're having the following types:
DataSource
DataType
View
I created multible directories under the app folder to hold these:
app/data_source
app/data_type
app/view
More types will follow and I'm a little worried with polluting the app folder with so many directories. Thus i want to move them into a subdirectory/module that holds all Types defined by the cms.
All classes should be inside a MyCms namespace and the directory layout should look like this:
app/my_cms/data_source
app/my_cms/data_type
app/my_cms/view
But now I'm having trouble with autoloading because rails default autoloading would excpect the paths to be like this:
app/data_source/my_cms
app/data_type/my_cms
app/view/my_cms
But this way I would not have grouped all object types in one directory.
What I want is somewhat similar to view grouping of isolated engines. In Devise for example, all views are grouped in the views/devise subdirectory.
Any idea how this could be achieved without to much custom implementation?
You would have to add app/my_cms to your autoload path within config/application.rb:
config.autoload_paths << "#{config.root}/app/my_cms"
provided that your classes are defined without a namespace like this:
class DataSource
...
end
If you namespace them like this in app/my_cms/data_source.rb:
class MyCms::DataSource
...
end
you might add the app folder to the load path:
config.autoload_paths << "#{config.root}/app"
Alternatively, you can do it manually but you lose the reloading for those classes in Rails development:
in app/my_cms.rb (and with autoloading for app in place):
module MyCms
autoload :AnotherDataSource, 'my_cms/data_source/one_data_source'
autoload :AnotherDataSource, 'my_cms/data_source/another_data_source'
...
end

Resources