Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 230 Vote(s) - 3.45 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Nested classes versus compact in Ruby

#1
Working on an initial Rails project, and using [Rubocop](

[To see links please register here]

) to analyze code style. It led me to question exactly how Ruby's nested classes work in the context of Rails. For example, in my engine, I have a model:

# app/models/app_core/tenant.rb
module AppCore
class Tenant < ActiveRecord::Base
end
end

and a controller:

# app/controllers/app_core/tenant/members_controller.rb
module AppCore
class Tenant::MembersController < ApplicationController
end
end

In the model's case, the module is the same as the path and the class name is the same as the file name. In the controllers case, the second part of the path, "tenant" is part of the class name.

Rubocop tells me that I should "Use nested class definitions instead of compact style" in the `Tenant::MembersController` line, so if I understand correctly...

module AppCore
class Tenant
class MembersController < ApplicationController
end
end
end

...this shouldn't make a difference.

Now, my question is I have AppCore::Tenant as a model, but then AppCore::Tenant looks to be reopened and the MembersController class is added to it as a nested class. Does this mean that my Tenant class will always have that nested class in it? Do I need to name my models and controller routes something differently? Is this totally fine and nothing to worry about? Not exactly sure what this means.
Reply

#2
If you are using nested and want to go back to the top-level nampespace you can use `::`.



def class user < ActiveRecord::Base
NAME = "Real User"
end

module SomeModule
def class User
Name = "Fake User"
end
module InnerModule
class MyClass
puts User.NAME # "Fake User"
puts ::User.Name # "Real User"
end
end
end

Reply

#3
I am aware that you are asking about the technical specifics, and Sami has answered that. But I can't help myself and have to ask:

Is there a particular reason in the first place why you want to...

1. ...introduce a "path" like hierarchy?
2. ...place the controller inside a model class?

If I would feel the need for 1), I would probably have simple "container" modules echoing the real paths. That is, `app/model/tenant.rb` => `Model::Tenant` and `app/controller/members_controller.rb` => `Controller::MembersController`.

But frankly, I don't really see the reasoning behind it. Controllers are already easilly spotted by the `XyzController` convention. Models are (most times, I guess) rather easily recognized by their domain-like nature. Since ruby does not require or even suggest to match path names to class names (unlike Java, for example), a clear 1-level naming convention would be more useful to me.

Submodule/subclass hierarchies _are_ very useful, or rather required, for gems, where they function like namespaces to avoid clashes.

2) (Controller inside a Model) is fundamentally wrong. Controllers are very very different from Models and certainly do not live inside one.
Reply

#4
One subtle difference is that your scope is different, and this can cause errors. In the first case constants will be looked up in `AppCore`, whereas in the second case constants will be looked up in `AppCore::Tenant`. If you fully qualify constant names then it doesn't make a difference.

Foo = :problem

module A
Foo = 42

# looks up A::Foo because of lexical scope
module B
def self.foo
Foo
end
end
end

# looks up ::Foo because of lexical scope
module A::C
def self.foo
Foo
end
end

# Looks up A::Foo, fully qualified ... ok technically ::A::Foo is fully qualified, but meh.
module A::D
def self.foo
A::Foo
end
end

A::B.foo # => 42
A::C.foo # => :problem
A::D.foo # => 42


If you are referring to constants defined in `AppCore::Tenant` from within `MembersController` then it might make a difference for you. Subtle but possibly important, and good to be aware of. I've hit this in real life when I had a `Util` module with a `String` submodule. I moved a method into `Util` and it broke because `String` inside that method now referred to `Util::String`. I changed some naming conventions after that.

Your `Tenant` module will always have `MembersController` as a nested class. Anywhere else in your codebase you can refer to `AppCore::Tenant::MembersController`. If you want better separation then you should name your model classes differently, or put them inside a module such as `AppCore::Model` or similar. If you're using Rails you'll have to buck some conventions, but the configuration required for that is not too bad.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through