2014-04-10 13 views
5

Próbuję edytować/zaktualizować rekord modelu za pomocą simple_form, ale formularz nie zmieni bezpośrednio pola modelu. Zamiast tego, oferuję kilka pól check_box_tag, które informują o aktualizacji, które pola wymagają zmiany. W rezultacie aktualizacja nie otrzymuje wartości skrótu [: device], której można użyć do aktualizacji atrybutów. Próbuję utworzyć ten skrót, ale otrzymuję komunikat ForbiddenAttributesError, gdy uruchamiam @ device.update_attributes (parametry [: device]).ActiveModel :: ForbiddenAttributesError przy użyciu update_attributes, które utworzyło mieszanie params ja

Wierzę, że moja lista silnych parametrów jest poprawna. Jeśli zezwalam na przetwarzanie jednego pola modelu (nazwy) w widoku edycji, otrzymuję oczekiwane parametry [: device] hash i wszystko działa. Jeśli wyłączę to pole, ponieważ nie chcę, aby zostało ono zmienione, muszę je utworzyć osobiście i otrzymam błąd. Kiedy patrzę na hasz, który utworzyłem, wygląda na to, że jest to odpowiednik tego, który przeszedł przez widok. Nie rozumiem, dlaczego to się nie udaje.

Środowisko to Ruby 2.0.0, Rails 4.1 w systemie Windows 8.1 z RubyMine 6.3.

Formularz jest: < ... potrzebuje poprawnego formatowania raz praca ...>

<%= simple_form_for @device do |f| %> 
     <legend><%= controller.action_name.capitalize %> Device:</legend> 
     <%= f.input :name, disabled: true %> 
     <%= check_box_tag(:is_admin, 0, @device.admin?) %> 
     <%= label_tag(:is_admin, "Make admin?") %> 
     <%= check_box_tag(:chg_pwd) %> 
     <%= label_tag(:chg_pwd, "Change password?") %> 
     <%= f.button :submit %> 
<% end %> 

params [:], że urządzenie otrzyma Kiedy wysłałem f.input: imię, niepełnosprawnych: false i pozwól widokowi generować parametry [: urządzenie] to:

I wszystko działa.

params [:] Urządzenie, które tworzę jest:

ActionController::Parameters (3 element(s)) 
"{"name"=>"D106", "password"=>"D106VdAd", "password_confirmation"=>"D106VdAd"}" 

A ja otrzymać Zakazane atrybutu błąd, chociaż nie widzę różnicy między nimi.

Aktualizacja jest: < ... Kod musi refactored, raz to działa ...>

class DevicesController < ApplicationController 
    before_filter :authenticate_device! 

... other methods removed here ... 

    def edit 
    @device = Device.find(params[:id]) 
    # my_page = render_to_string controller: 'devices', action: 'edit', layout: "application" 
    end 

    def update 
    authorize! :update, @device, :message => 'Not authorized as an administrator.' 
    @device = Device.find(params[:id]) 
    pwd_msg = "" 
    if params[:chg_pwd] 
     pwd_gen = @device.device + SecureRandom.urlsafe_base64(15).tr('lIO0=_\-', 'sxyzEUM').first(4) 
     params[:device] = {name: @device.name} if params[:device].nil? 
     params[:device][:password] = pwd_gen 
     params[:device][:password_confirmation] = pwd_gen 
     pwd_msg = ", new password is #{pwd_gen}" 
    end 
    if @device.update_attributes(params[:device]) 
     params[:is_admin] ? @device.add_role(:admin) : @device.remove_role(:admin) 
     flash[:notice] = ["Device updated" + pwd_msg] 
     redirect_to devices_path 
    else 
     @device.errors.messages.each do |key, value| 
     flash[:alert] = ["Unable to update device"] 
     @device.errors.messages.each do |key, value| 
      flash[:alert] << key.to_s.capitalize + " " + value[0] 
     end 
     end 
     redirect_to devices_path 
    end 
    end 

    private 

    def device_params 
    params.require(:device).permit(:device, :name, :email, :password, :password_confirmation, :encrypted_password, :salt, :role_ids, :is_admin, :chg_pwd) # TODO minimize when update is working 
    end 

end 

Model jest:

class Device < ActiveRecord::Base 

    rolify 
    devise :database_authenticatable, :rememberable, :trackable, :validatable 

    validates :device, 
      presence: true, 
      length: {minimum: 4 }, 
      uniqueness: {case_sensitive: false } 
    validates :name, 
      presence: true 

    def remember_me 
    true unless self.admin? 
    end 

    def admin 
    self.add_role :admin 
    end 

    def not_admin 
    self.remove_role :admin 
    end 

    def admin? 
    self.has_role? :admin 
    end 
    def device? 
    self.has_role? :device 
    end 
    def vip? 
    self.has_role? :vip 
    end 

    def login=(login) 
    @login = login 
    end 
    def login 
    @login || self.device || self.email 
    end 

    def self.find_first_by_auth_conditions(warden_conditions) 
    conditions = warden_conditions.dup 
    if login = conditions.delete(:login) # Note one equal sign. Strange but true. 
     where(conditions).where(["lower(device) = :value OR lower(email) = :value", { :value => login.downcase }]).first 
    else 
     where(conditions).first 
    end 
    end 

end 

NOWE INFORMACJE: I zaniedbane dostarczenie informacji Mam w ApplicationController. Ta poprawka Anton Trapp obsługuje silne parametry klejnotów, które nie są jeszcze w pełni kompatybilny Szyny 4:

before_filter do 
    resource = controller_name.singularize.to_sym 
    method = "#{resource}_params" 
    params[resource] &&= send(method) if respond_to?(method, true) 
    end 

I odkryli, że za pomocą proponowanego rozwiązanie:

@device.update_attributes(device_params) 

nie działa, jeśli model pole jest aktualizowane. Rezultatem jest "nie znaleziono parametru: urządzenie". Działa, jeśli żadne pole modelu nie jest aktualizowane. Cała ta kwestia nasuwa pytanie o to, co jest naprawdę złe.

Odpowiedz

1

Rozwiązaniem było dodanie pola jako attr_accessor do modelu, ale nie jest to baza danych, aby mogła być poprawnie użyta w formularzu.

attr_accessor :is_admin, :chg_pwd 

A potem modyfikować celu:

<%= simple_form_for @device do |f| %> 
    <legend><%= controller.action_name.capitalize %> Device:</legend> 
    <%= f.input :name, disabled: true %> 
    <%= f.input :is_admin, as: :boolean, checked_value: true, unchecked_value: false %> 
    <%= f.input :chg_pwd, as: :boolean, checked_value: true, unchecked_value: false %> 
    <%= f.button :submit %> 
<% end %> 

Następnie, ze względu na kod kontrolera Zastosowanie Anton Trapp:

before_filter do 
    resource = controller_name.singularize.to_sym 
    method = "#{resource}_params" 
    params[resource] &&= send(method) if respond_to?(method, true) 
    end 

udało mi się zaktualizować pola w kontrolerze Device w następujący sposób:

@device.update_attributes(params[:device]) 
3

W DevicesController#update działania, zmień

@device.update_attributes(params[:device]) 

Aby

@device.update_attributes(device_params) 

Jak używasz Rails 4.1, trzeba białej listy atrybutów, które chcieliby Państwo być wstawiony/zaktualizowany w bazie danych.Jak zdałeś atrybuty bezpośrednio do update_attributes metody bez pozwalając im otrzymaniu ActiveModel::ForbiddenAttributesError

UPDATE

Aby rozwiązać param not found: device:

def device_params 
    if params[:device] 
     params.require(:device).permit(:device, :name, :email, :password, :password_confirmation, :encrypted_password, :salt, :role_ids, :is_admin, :chg_pwd) # TODO minimize when update is working 
    end 
    end 
+0

Okay, zmiana ma sens i działa. Nadal zastanawiam się, dlaczego działało to tak, jak było, gdy chodziło o pole modelowe? Wiesz to? Dzięki ... –

+0

"dlaczego zadziałało tak, jak było, gdy zaangażowane było pole modelowe?" Oznacza? Które pole modelu? Czy masz na myśli, że ten sam kod działał w każdym przypadku? –

+0

W widoku edycji, jeśli użyję "f.input: name, disabled: false", wówczas parametry [: device] zostaną wysłane do akcji aktualizacji z ustawieniem parametrów params: set [: davice] [: name]. W takim przypadku akcja aktualizacji działała tak jak ją miałem. Jeśli zamiast tego użyję "f.input: name, disabled: true", tak, że pola nazwy nie można zmienić, niż parametry [: device] is nil. Aby zaktualizować atrybuty, zbudowałem parametry [: urządzenie], jak pokazano. Oba skróty są równoważne. Ale otrzymałem ForbiddenAttributeError na haszach, które zbudowałem, mimo że ten, który został stworzony dla mnie przez edycję, działał przy użyciu @ device.update_attributes (parametry [: device]). –

Powiązane problemy