2010-11-16 15 views
13

He estado impidiendo cambios a ciertos modelos mediante el uso de esta en el modelo:¿Cómo puedo denegar actualizaciones excepto en un campo?

def update 
    self.errors.add_to_base("Cannot update a #{ self.to_s }") 
end 

Ahora estoy escribiendo un plugin que ofrece algunas funciones extra para el modelo, y necesito actualizar un campo en el modelo. Si yo no estuviera usando un plugin Me gustaría hacer esto directamente en el modelo ...

def update 
    if self.changed == ['my_field'] 
    super 
    else 
    self.errors.add_to_base("Cannot update a #{ self.to_s }")  
    end 
end 

no puedo hacer lo mismo de mi plug-in, ya que no sé si el comportamiento de actualización es el valor predeterminado ActiveRecord o ha sido anulado para evitar actualizaciones. ¿Hay alguna otra manera de evitar las actualizaciones de registros al mismo tiempo que me permite anular para un campo específico (y solo en la instancia en que se aplica mi complemento a este modelo).

Respuesta

10

En primer lugar, debe utilizar una devolución de llamada before_update para ese tipo de cosas en lugar de anular la actualización. En segundo lugar, puede almacenar los atributos actualizables en el modelo y luego actualizarlos con el complemento. Acabo de escribir esto en el navegador, por lo que podría estar mal.

attr_accessor :updatable_attributes 
    before_update :prevent_update 

    private 
    def prevent_update 
    return true if self.changed == self.updatable_attributes 
    self.errors.add_to_base "Cannot update a #{ self.to_s }" 
    false 
    end 
end 
+0

Gracias. Me di cuenta de que los modelos que requieren mi lógica prevent_update también son los que requieren el complemento, así que he movido todo al plugin, usando un filtro before_update como sugieres. – Nick

+4

En rieles 3. *, agregue el error mediante 'self.errors.add: base," No se puede actualizar ... "' – ronen

+1

Creo que probablemente desee que la cláusula if sea más bien 'return true si self.changed | self. updatabale_attributes == self.updatabale_attributes' para que también pueda actualizar un subconjunto de los atributos actualizables. – Timo

0

¿Esto es para evitar la asignación masiva? ¿Attr_accessible/attr_protected no haría lo que necesita?


Editar, para ilustrar el punto general acerca de la devolución de llamada.

module MyModule 
    def MyModule.included(base) 
    base.send :alias_method_chain, :prevent_update, :exceptions 
    end 

    def prevent_update_with_exceptions 
    end 
end 

class MyModel < ActiveRecord::Base 
    before_validation :prevent_update 

    def prevent_update 
    end 

    include MyModule 
end 
+0

No, es para hacer cumplir las reglas comerciales a nivel de modelo. Hacer attr_readonly para cada campo excepto uno podría hacer el trabajo, pero es bastante detallado. – Nick

+0

¿Qué tal una devolución de llamada previa a la validación? Puede verificar qué atributos han cambiado y si el modelo es nuevo y luego evitar la actualización. – allan

+0

No estoy seguro de entender completamente su sugerencia ... está diciendo que agregue una devolución de llamada before_valida en el modelo que evitará las actualizaciones. Luego, en mi complemento, ¿qué debo hacer para permitir una actualización en un campo? – Nick

4

tarde al juego aquí, pero para las personas que visitan esta pregunta, puede utilizar attr_readonly permitir la escritura sobre un campo en crear, pero no permitir actualizaciones.

Ver http://api.rubyonrails.org/classes/ActiveRecord/ReadonlyAttributes/ClassMethods.html

creo que ha estado disponible desde Rails 2.0

La parte difícil es, si tiene alguna atributos que se attr_accessible tienes a tu lista de sólo lectura atributos también (o que presentamos lo mejor un error de masa misión en crear):

class Post < ActiveRecord::Base 
    attr_readonly :original_title 
    attr_accessible :latest_title, :original_title 
end 
+0

mdkirby, ¿podría echar un vistazo a este? Siento que está conectado a esta respuesta. http://stackoverflow.com/questions/33357501/rails-attribute-changes-in-spite-of-not-being-in-form –

0

sólo tiene que utilizar los carriles params.require método para la lista blanca atributos que desea permitir.

def update 
    if @model.update(update_model_params) 
    render json: @model, status: :ok 
    else 
    render json: @model.errors, status: :unprocessable_entity 
    end 
end 

private 
    def update_prediction_params 
    params.require(:model).permit(:editable_attribute) 
    end 
Cuestiones relacionadas