Params.require(...).permit(...)

Cześć,

/Rails 5.1.2, Ruby 2.4.1, Postgress 9.5/

Mam model:

class CreateRoles < ActiveRecord::Migration[5.1]
  def change
    create_table :roles do |t|
      t.string :name
      t.boolean :special, null: false, default: false, index: true
      t.string :activities, array: true, using: 'gin', default: '{}'
      t.text :note, default: ""

      t.timestamps
    end
  end
end

na _form pole activities edytuję jako
f.text_field :activities

do controllera trafia:

Processing by RolesController#update as HTML
Parameters: {“utf8”=>“✓”, “authenticity_token”=>“dZXVxB+Q8NtESy9fsxRLs8YCG7R6AkuIdRQKSr8GMWYodB10I1ZNVonrtxzjWQSdiTM8IlBWkurv3i5KRZZaUg==”, “role”=>{“name”=>“Customers Admin”, “special”=>“1”, “note”=>“ble, ble”, “activities”=>“customer:index customer:show customer:create customer:update customer:delete”}, “commit”=>“Update Role”, “id”=>“21”}

gdy w akcji update mam wymienione paramatry i split na params[:role][:activities]

  def update
    @role = Role.find(params[:id])
    respond_to do |format|
      if @role.update(name: params[:role][:name], note: params[:role][:note], special: params[:role][:special],activities: params[:role][:activities].split)
        flash[:success] = t('activerecord.successfull.messages.updated', data: @role.fullname)
        format.html { redirect_to @role }
        format.json { render :show, status: :ok, location: @role }
      else
        format.html { render :edit }
        format.json { render json: @role.errors, status: :unprocessable_entity }
      end
    end
  end

to wszystko się elegancko zapisuje.
Chcę jednak użyć zamiast
if @role.update(name: params[:role][:name], note: params[:role][:note], special: params[:role][:special],activities: params[:role][:activities].split)

konwencji:
if @role.update(role_params)


oraz

private
  def role_params
    params.require(:role).permit(:name, :note, :activities, :special)
  end

Jak zawartość permit(…) winna być zdefiniowana, by przyjmował activities jako tablicę?
P.S.
Nawet, gdy wcześniej w akcji update robię:
params[:role][:activities] = params[:role][:activities].split
to do bazy zapisywana jest pusta tablica [] i dostaję info w logu info:

Unpermitted parameter: :activities

No z tym przykładem

params.require(:luchador).permit(:favorite_move, :weight, wins: [])

nawiasu klamrowego robiłem, ale chyba kluczowy jest wiersz powyżej czyli:

params[:luchador][:wins] ||= []

Spróbuję przećwiczyć
Dzięki :slight_smile:

def role_params
  params[:role][:activities] ||= []
  params.require(:role).permit(:name, :note, :special, activities: [])
end

niestety, nadal dostaję:

Started PATCH “/roles/21” for 127.0.0.1 at 2017-08-23 14:57:12 +0200
Processing by RolesController#update as HTML
Parameters: {“utf8”=>“✓”, “authenticity_token”=>“c9zOWWMQXKRjcU7cqtD/x9h+NjvmuW1gVCTCqgtkbvK3E5/dm8S9t/84vDy3BQ0tq3OuS87XNWUiDpE8lIJiBA==”, “role”=>{“name”=>“Customers Admin”, “special”=>“1”, “note”=>“ble ble”, “activities”=>“customer:index customer:show customer:create”}, “commit”=>“Update Role”, “id”=>“21”}
User Load (1.4ms) SELECT “users”.* FROM “users” WHERE “users”.“id” = $1 ORDER BY “users”.“id” ASC LIMIT $2 [[“id”, 1], [“LIMIT”, 1]]
Role Load (1.2ms) SELECT “roles”.* FROM “roles” WHERE “roles”.“id” = $1 LIMIT $2 [[“id”, 21], [“LIMIT”, 1]]
Role Load (0.9ms) SELECT DISTINCT “roles”.“activities” FROM “roles” INNER JOIN “roles_users” ON “roles”.“id” = “roles_users”.“role_id” WHERE “roles_users”.“user_id” = $1 [[“user_id”, 1]]
Unpermitted parameter: :activities

…Nie wiem, czy to nie jest jakaś przypadłość wersji 5 railsów

czy params[:role][:activities] jest stringiem czy tablicą ?

[quote="BSorbus, post:1, topic:14708"]

Parameters: {“utf8”=>“✓”, “authenticity_token”=>“dZXVxB+Q8NtESy9fsxRLs8YCG7R6AkuIdRQKSr8GMWYodB10I1ZNVonrtxzjWQSdiTM8IlBWkurv3i5KRZZaUg==”, “role”=>{“name”=>“Customers Admin”, “special”=>“1”, “note”=>“ble, ble”, “activities”=>“customer:index customer:show customer:create customer:update customer:delete”}, “commit”=>“Update Role”, “id”=>“21”}
[/quote]

…czyli jest stringiem

czyli to string, a w bazie jest tablica,

permit(activities: []) nie zadziała na stringu, musisz w akcji kontrolera to rozdzielić i dopiero wtedy zapisać do bazy

To wrócę do pierwszego pytania.

Co powinienem mieć w kontrolerze i co w definicji

def role_params
...
end

?

pole w bazie jest zdefiniowane jako tablica:

t.string :activities, array: true, using: 'gin', default: '{}'

a do kontrolera trafia:
“role”=>{“name”=>“Customers Admin”, “special”=>“1”, “note”=>“ble, ble”, “activities”=>“customer:index customer:show customer:create customer:update customer:delete”}

…tak zrobiłem, co jest opisane w pierwszym poście, jednakże nie wiem, jak to zrobić elegancko posługując się def role_params

Wszystkie pola poza activities możes przepuścić przez Strong Parameters z pominięciem activities które musisz ręcznie rozbić. Można to w różny sposób zapisać np.

def role params
  activities = params[:role][:activities].split || []
  params.require(:role).permit(:name, :note, :special).merge(activities: activities)
end

pamiętaj o zabezpieczeniu przypadków brzegowych (np. gdy activities będzie nilem, itd.)

… później sprawdzę, czy “zaskoczyło”.

Dzięki za pomoc :slight_smile:

Started POST “/roles” for 127.0.0.1 at 2017-08-23 19:06:00 +0200
Processing by RolesController#create as HTML
Parameters: {“utf8”=>“✓”, “authenticity_token”=>“uC2lJXdC4xCMkjFiWteYBgj3sQXCAtxIZBXwKrMg1cFhce71bv+8bufP0Npb5m/XoumiIUZ29N95cPPoT2OpzQ==”, “role”=>{“name”=>“Customers Admin”, “special”=>“0”, “note”=>“ble ble”, “activities”=>“customer:index customer:show customer:create customer:update customer:delete”}, “commit”=>“Utwórz Rola”}
User Load (0.6ms) SELECT “users”.* FROM “users” WHERE “users”.“id” = $1 ORDER BY “users”.“id” ASC LIMIT $2 [[“id”, 1], [“LIMIT”, 1]]
Unpermitted parameter: :activities
Role Load (0.8ms) SELECT DISTINCT “roles”.“activities” FROM “roles” INNER JOIN “roles_users” ON “roles”.“id” = “roles_users”.“role_id” WHERE “roles_users”.“user_id” = $1 [[“user_id”, 1]]
(0.6ms) BEGIN
Role Exists (0.4ms) SELECT 1 AS one FROM “roles” WHERE LOWER(“roles”.“name”) = LOWER($1) LIMIT $2 [[“name”, “Customers Admin”], [“LIMIT”, 1]]
SQL (0.9ms) INSERT INTO “roles” (“name”, “activities”, “note”, “created_at”, “updated_at”) VALUES ($1, $2, $3, $4, $5) RETURNING “id” [[“name”, “Customers Admin”], [“activities”, “{customer:index,customer:show,customer:create,customer:update,customer:delete}”], [“note”, “ble ble”], [“created_at”, “2017-08-23 17:06:00.165357”], [“updated_at”, “2017-08-23 17:06:00.165357”]]
(3.0ms) COMMIT
Redirected to http://localhost:3000/roles/25
Completed 302 Found in 26ms (ActiveRecord: 6.4ms)

Działa, zapisuje do bazy …aczkolwiek nadal w logu jest:
Unpermitted parameter: :activities

Dzięki za pomoc :slight_smile:

No nic dziwnego, że masz INFO że nie przepuszczone, bo tak na prawdę jest. Dopiero po whitelistowaniu merdżujesz klucz z wartościami do zwróconego przez permit hasha.

Tak, też zwróciłem uwagę na

params.require(:role).permit(:name, :note, :special).merge......

Moja uwaga, że się w logu nadal odkłada ten komunikat była raczej zawoalowaną formą pytania, czy nie da się tego jeszcze lepiej zrobić. :slight_smile:

na przykład

def role params
  params.require(:role).permit(:name, :note, :special, :activities).tap do |parameters|
    parameters[:activities] = parameters[:activities].try(:split)
  end
end
2 Likes

Czapki z głów!

Super!
Dzięki :slight_smile: