Ror - Get controller Strong files inside the Application Controller

Asked

Viewed 152 times

2

I am developing a logging process on my system (Rails 5), more specifically within the application controller. This process is being created there so I can add one before_save us controllers that I want to record logs. As are several controllers, I am centralizing the method instead of repeating it several times in each file.
The logging process works like this: when the user clicks on the "Save" button on form editing, the system fetches in the BD the current record of the object the user is editing and compare these records with the fields of the form. If the records are different, it means that the user has changed some data. The old data is saved as log and the new data is saved to the BD.
Follow down what I’ve got so far:

def gerar_log
    @controlr = instance_variable_get("@#{controller_name.singularize}") #objeto que está sendo editado
    nome_cols = @controlr.attribute_names #pega o nome das colunas da tabela do objeto
    ctrl_obj = @controlr.attributes #pega os dados do objeto do BD
    dados_editados = self.strong_params #pega os strong params do controller, que contém o que foi alterado nos campos do form. Estou preso aqui =/
    ...
    ##compara os dados_editados com os dados atuais do objeto e verifica se algo mudou
end

The problem I’m having in this process is time to catch the strong parameters of controller. How is a method private, can’t call him directly. I tried to create a method public, called strong_params, that returns the params of the private method, but it generates the following error: param is missing or the value is empty:. If anyone knows of a solution to this or if there is some better and equally dynamic way to do this process that is not within the application controller, I am grateful if you can inform me.

EDIT - I do not intend to use gems for this process, because it is something super simple. The only obstacle at the moment is to dynamically obtain the strong parameters of each controller. If I can’t do it inside application_controller, I can do by defining a method within each controller as follows:

../controllers/persons_controller.erb

def log
    @pessoas = Pessoa.find(params[:id]) #busca a pessoa que está sendo editada
    colunas = @pessoas.attribute_names #pega o nome das colunas da tabela pessoa
    parametros = pessoa_params.merge(:id => params[:id]) #pega os dados que estão sendo editados no form e adiciona o ID
    pess = @pessoas.attributes #pega os dados da pessoa do BD
    alteracoes = {}

    colunas.each_index do |i|
    ##compara os dados_editados com os dados atuais do objeto e verifica se algo mudou
    #Se mudou, atualiza a pessoa com os novos dados e salva os dados antigos na tabela de log
      if parametros[colunas[i]].to_s != pess[colunas[i]].to_s 
        alteracoes[colunas[i]] = pess[colunas[i]].to_s unless parametros[colunas[i]].nil?
      end

    end

    @logs = Log.new
    @logs.gera_log(current_user.id, controller_name, params[:id], alteracoes) unless alteracoes.nil? || alteracoes.empty?

  end

To generate log before the user updates the information:

before_save :log, only: [:update]

The bright side of this is that it does exactly what I need. The bad side is that I need to define this method in each controller that I want to generate log, and that goes against policy DRY (Don't Repeat Yourself). So I want to know if there’s a way to centralize this method and make it dynamic for each controller, without using gems!

  • 1

    You don’t do that in the controller, but in the model. There’s a Gem that does what you need, https://github.com/collectiveidea/audited

1 answer

1

The best way I know how to do this is by using Gem Paper Trail, it is extremely dynamic and effective for this type of solution. I use it a lot in my projects for audit, versioning and recovering data.

In the case of this Gem the data will be recorded in the database and not in logs, but do not worry, it generates its own Migrations. Then just add one before_action in his ApplicationController:

class ApplicationController
  before_action :set_paper_trail_whodunnit
end

And inform in each model who will be audited by PaperTrail:

class Widget < ActiveRecord::Base
  has_paper_trail
end

It is extremely customizable and powerful, for this I recommend reading its README.

I believe she falls like a glove to your need.

  • Thanks for the @Luizcarvalho reply, but I don’t intend to use gems for this process. I updated my question with an "alternative" method that is already working. But my wish is to center it dynamically.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.