Overriding model name in Rails
Rails automatically generates URLs for redirect_to
, form_for
methods based on the provided object (via ActionDispatch::Routing::UrlFor#url_for). Sometimes, there are situations when we want to customize that (i.e. object is namespaced).
Let’s look at simple Identity::Session
object:
module Identity
class Session
...
end
end
Passing Identity::Session
instance to form_for
helper will use session_identities_path
method as an action
attribute.
This can be changed by overriding Identity::Session.model_name
method with some help from ActiveModel::Name.
ActiveModel::Name
can automatically detect namespace
and name
based on the provided klass
:
naming = ActiveModel::Name.new(Identity::Session)
naming.name
#> "Identity::Session"
naming.route_key
#> "session_identities"
It also accepts klass
, namespace
and name
as separate arguments to override its default behavior:
naming = ActiveModel::Name.new(Identity::Session, nil, "Session")
naming.name
#> "Session"
naming.route_key
#> "sessions"
They can be even used to change the namespace:
naming = ActiveModel::Name.new(Identity::Session, Identity, "Logins::Session")
naming.name
#> "Logins::Sessions"
naming.route_key
#> "logins_sessions"
Now we just need to use it to override Identity::Session.model_name
method, according to our needs:
module Identity
class Session
def self.model_name
ActiveModel::Name.new(self, nil, "Session")
end
end
end
After that, Identity::Session
instance can be passed to form_for
or redirect_to
methods.
URLs can be verified with ActionDispatch::Routing::UrlFor#url_for
method in the rails console
:
include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
Rails.application.routes.default_url_options = { host: 'localhost:3000' }
url_for(session)
#> "http://localhost:3000/sessions"
Thank you @amatchneer for spotting typos!