Update models customization documentation

This commit is contained in:
Javi Martín
2024-08-19 18:24:27 +02:00
parent d3fa99332c
commit fce300a11a
2 changed files with 96 additions and 120 deletions

View File

@@ -1,75 +1,63 @@
# Models
# Customizing models
If you need to create new models or customize existent ones, you can do it so at the `app/models/custom` folder. Keep in mind that for old models you'll need to firstly require the dependency.
In order to create new models or customize existing ones, you can use the `app/models/custom/` folder.
For example for Madrid's City Hall fork its required to check the zip code's format (it always starts with 280 followed by 2 digits). That check is at `app/models/custom/verification/residence.rb`:
If you're adding a new model that doesn't exist in the original Consul Democracy, simply add it to that folder.
If, on the other hand, you are changing a model that exists in the application, create a file in `app/models/custom/` with same name as the file you're changing. For example, if you're changing the `app/models/budget/investment.rb` file, create a file named `app/models/custom/budget/investment.rb` and require the original one:
```ruby
load Rails.root.join("app", "models", "verification", "residence.rb")
load Rails.root.join("app", "models", "budget", "investment.rb")
class Verification::Residence
validate :postal_code_in_madrid
validate :residence_in_madrid
def postal_code_in_madrid
errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code?
class Budget
class Investment
end
def residence_in_madrid
return if errors.any?
unless residency_valid?
errors.add(:residence_in_madrid, false)
store_failed_attempt
Lock.increase_tries(user)
end
end
private
def valid_postal_code?
postal_code =~ /^280/
end
end
```
Do not forget to cover your changes with a test at the `spec/models/custom` folder. Following the example we could create `spec/models/custom/residence_spec.rb`:
Since the custom file requires the original one, at this point, the custom model will behave exactly as the original.
Note that, if we do not require the original file, that file won't be loaded and the custom model will do nothing, which will likely result in errors.
## Adding new methods
In order to add a new method, simply add the new code to the model. For example, let's add a scope that returns the investments created last month:
```ruby
require 'rails_helper'
describe Verification::Residence do
let(:residence) { build(:verification_residence, document_number: "12345678Z") }
describe "verification" do
describe "postal code" do
it "should be valid with postal codes starting with 280" do
residence.postal_code = "28012"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
residence.postal_code = "28023"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
end
it "should not be valid with postal codes not starting with 280" do
residence.postal_code = "12345"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
residence.postal_code = "13280"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.")
end
end
load Rails.root.join("app", "models", "budget", "investment.rb")
class Budget
class Investment
scope :last_month, -> { where(created_at: 1.month.ago..) }
end
end
```
With this code, the custom model will have all the methods of the original model (because it loads the original file) plus the `last_month` scope.
## Modifying existing methods
When modifying existing methods, it is strongly recommended that, when possible, **your custom code calls the original code** and only modifies the cases where it should behave differently. This way, when upgrading to a new version of Consul Democracy that updates the original methods, your custom methods will automatically include the modifications in the original code as well. Sometimes this won't be possible, though, which means you might need to change your custom method when upgrading.
For example, to change the common abilities model so only verified users can create comments, we'll create a file `app/models/custom/abilities/common.rb` with the following content:
```ruby
load Rails.root.join("app", "models", "abilities", "common.rb")
module Abilities
class Common
alias_method :consul_initialize, :initialize # create a copy of the original method
def initialize(user)
consul_initialize(user) # call the original method
cannot :create, Comment # undo the permission added in the original method
if user.level_two_or_three_verified?
can :create, Comment
end
end
end
end
```
You can find another example in the `app/models/custom/setting.rb` file.

View File

@@ -1,75 +1,63 @@
# Modelos
# Personalización de modelos
Si quieres agregar modelos nuevos, o modificar o agregar métodos a uno ya existente puedes hacerlo en `app/models/custom`. En el caso de los modelos antiguos debes primero hacer un require de la dependencia.
Si quieres agregar modelos nuevos, o modificar o agregar métodos a uno ya existente, puedes utilizar el directorio `app/models/custom/`.
Por ejemplo en el caso del Ayuntamiento de Madrid se requiere comprobar que el código postal durante la verificación sigue un cierto formato (empieza con 280). Esto se realiza creando este fichero en `app/models/custom/verification/residence.rb`:
Si estás añadiendo un nuevo modelo que no existe en el código original de Consul Democracy, simplemente añade el modelo a ese directorio.
Si, por el contrario, estás cambiando un modelo que existe en la aplicación, crea un fichero en `app/models/custom/` con el mismo nombre que el fichero que estás cambiando. Por ejemplo, para cambiar el fichero `app/models/budget/investment.rb`, crea un fichero llamado `app/models/custom/budget/investment.rb` que cargue el original:
```ruby
load Rails.root.join("app", "models", "verification", "residence.rb")
load Rails.root.join("app", "models", "budget", "investment.rb")
class Verification::Residence
validate :postal_code_in_madrid
validate :residence_in_madrid
def postal_code_in_madrid
errors.add(:postal_code, I18n.t('verification.residence.new.error_not_allowed_postal_code')) unless valid_postal_code?
class Budget
class Investment
end
def residence_in_madrid
return if errors.any?
unless residency_valid?
errors.add(:residence_in_madrid, false)
store_failed_attempt
Lock.increase_tries(user)
end
end
private
def valid_postal_code?
postal_code =~ /^280/
end
end
```
No olvides poner los tests relevantes en `spec/models/custom`, siguiendo con el ejemplo pondriamos lo siguiente en `spec/models/custom/residence_spec.rb`:
Como el fichero personalizado carga el original, con este código el modelo personalizado se comportará exactamente igual que el original.
Nótese que, si no se carga el fichero original, el modelo personalizado no hará nada, lo cual hará que la aplicación no se comporte correctamente.
## Añadir nuevos métodos
Para añadir un método nuevo, simplemente añade el nuevo código al modelo. Por ejemplo, para añadir un método de tipo "scope" que devuelva los proyectos de gasto creados durante el último mes:
```ruby
require 'rails_helper'
describe Verification::Residence do
let(:residence) { build(:verification_residence, document_number: "12345678Z") }
describe "verification" do
describe "postal code" do
it "should be valid with postal codes starting with 280" do
residence.postal_code = "28012"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
residence.postal_code = "28023"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(0)
end
it "should not be valid with postal codes not starting with 280" do
residence.postal_code = "12345"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
residence.postal_code = "13280"
residence.valid?
expect(residence.errors[:postal_code].size).to eq(1)
expect(residence.errors[:postal_code]).to include("In order to be verified, you must be registered in the municipality of Madrid.")
end
end
load Rails.root.join("app", "models", "budget", "investment.rb")
class Budget
class Investment
scope :last_month, -> { where(created_at: 1.month.ago..) }
end
end
```
Con este código, el modelo personalizado tendrá todos los métodos del modelo original (ya que carga el archivo original) más el método de tipo "scope" `last_month`.
## Modificar métodos existentes
Al modificar métodos existentes, recomendamos encarecidamente que, siempre que sea posible, **tu código personalizado llame al código original** y solamente modifique los casos en que debería comportarse de forma diferente. De este modo, al actualizar a una nueva versión de Consul Democracy que actualice los métodos originales, tus métodos personalizados incluirán las modificaciones del código original automáticamente. En ocasiones, hacer esto no será posible, con lo cual tendrás que cambiar tu método personalizado al actualizar.
Por ejemplo, para cambiar el modelo `Abilities::Common` para que solamente los usuarios verificados puedan crear comentarios, crearemos el archivo `app/models/custom/abilities/common.rb` con el siguiente contenido:
```ruby
load Rails.root.join("app", "models", "abilities", "common.rb")
module Abilities
class Common
alias_method :consul_initialize, :initialize # create a copy of the original method
def initialize(user)
consul_initialize(user) # call the original method
cannot :create, Comment # undo the permission added in the original method
if user.level_two_or_three_verified?
can :create, Comment
end
end
end
end
```
Puedes encontrar otro ejemplo de modelo personalizado en el archivo `app/models/custom/setting.rb`.