Rails: Como obter o nome da classe do modelo com base no nome da classe do controlador?

99
class HouseBuyersController < ...
  def my_method
    # How could I get here the relevant model name, i.e. "HouseBuyer" ?
  end
end
Misha Moroshko
fonte

Respostas:

190

Isso vai resolver:

class HouseBuyersController < ApplicationController

  def index
    @model_name = controller_name.classify
  end

end

Isso geralmente é necessário ao abstrair ações do controlador:

class HouseBuyersController < ApplicationController

  def index
    # Equivalent of @house_buyers = HouseBuyer.find(:all)
    objects = controller_name.classify.constantize.find(:all)
    instance_variable_set("@#{controller_name}", objects)
  end

end
malclocke
fonte
@model_name = controller_name.classify # retorna "HouseBuyers" obrigado!
Peter Ehrlich
1
ActiveSupport :: Inflector é incrível
Jared Beck
Dependendo de suas necessidades, (esta questão não especifica nenhum detalhe), você pode fazer controller_name.sub('_', ' ').titleizepara obter "compradores de casa".
user664833
Pode ser bom mover a lógica (para obter a classe do modelo) para um método de utilitário separado. Melhor ainda se o resultado for armazenado em uma constante, para agilizar o acesso. Você pode usar new.controller_name.classify.constantizena definição da classe.
Kelvin
Acho que é importante notar que isso funcionará até no controlador de aplicativo, dependendo de qual controlador herda dele.
weltschmerz
40

Se o seu controlador e modelo estão no mesmo namespace, então o que você quer é

controller_path.classify

controller_pathfornece o namespace; controller_namenão.

Por exemplo, se o seu controlador é

Admin::RolesController

então:

controller_path.classify # "Admin::Role" # CORRECT
controller_name.classify # "Role"        # INCORRECT
Matt
fonte
6

É um pouco hackeado, mas se o nome do seu modelo for o nome do controlador:

class HouseBuyersController < ApplicationController
  def my_method
    @model_name = self.class.name.sub("Controller", "").singularize
  end
end

... daria a você "HouseBuyer" em sua variável de instância @model_name.

Novamente, isso faz uma grande suposição de que "HouseBuyersController" só lida com modelos "HouseBuyer".

Scott
fonte
4

Para namespaces funcionando:

def resource_class
 controller_path.classify.constantize
end
hachpai
fonte
0

Isso não é possível se você estiver usando o MVC padrão, que seu código parece não seguir. Seu controlador parece ser um modelo, mas talvez você só tenha um tipo aí. De qualquer forma, controladores e modelos são fundamentalmente separados no Rails MVC, então os controladores não podem saber a qual modelo estão associados.

Por exemplo, você pode ter um modelo chamado post. Isso pode ter um controlador posts_controller ou pode ter um controlador como o articles_controller. O Rails só conhece os modelos quando você define o código real no controlador, como

def index
  @posts = Post.all
  @posts = Article.all
end  

Em controladores padrão rails não há como saber qual é o modelo.

Thenengah
fonte
0

A solução aceita não funcionou para mim, pois meu controlador e modelo tinham namespace. Em vez disso, criei o seguinte método:

def controllers_model
  (self.class.name.split('::')[0..-2] << controller_name.classify).join('::')
end
Stoffus
fonte