jak zezwolić na tablicę o silnych parametrach

269

Mam działającą aplikację Rails 3, która korzysta z has_many: poprzez skojarzenia, które nie są, ponieważ zmieniam ją jako aplikację Rails 4, pozwalając mi zapisywać identyfikatory z powiązanego modelu w wersji Rails 4.

Są to trzy odpowiednie modele są takie same dla dwóch wersji.

Kategoryzacja. Rb

class Categorization < ActiveRecord::Base

  belongs_to :question
  belongs_to :category
end

Pytanie. Rb

has_many :categorizations
has_many :categories, through: :categorizations

Category.rb

has_many :categorizations
has_many :questions, through: :categorizations

W obu aplikacjach identyfikatory kategorii są przekazywane do akcji tworzenia w ten sposób

  "question"=>{"question_content"=>"How do you spell car?", "question_details"=>"blah ", "category_ids"=>["", "2"],

W aplikacji Rails 3, gdy tworzę nowe pytanie, wstawia się ono do tabeli pytań, a następnie do tabeli kategoryzacji

 SQL (82.1ms)  INSERT INTO "questions" ("accepted_answer_id", "city", "created_at", "details", "province", "province_id", "question", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [["accepted_answer_id", nil], ["city", "dd"], ["created_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["details", "greyound?"], ["province", nil], ["province_id", 2], ["question", "Whos' the biggest dog in the world"], ["updated_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["user_id", 53]]
  SQL (0.4ms)  INSERT INTO "categorizations" ("category_id", "created_at", "question_id", "updated_at") VALUES (?, ?, ?, ?)  [["category_id", 2], ["created_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["question_id", 66], ["updated_at", Tue, 14 May 2013 17:10:25 UTC +00:00]]

W aplikacji rails 4 po przetworzeniu parametrów w narzędziu QuestionController # create pojawia się ten błąd w dziennikach serwera

Unpermitted parameters: category_ids

a pytanie jest tylko wstawiane do tabeli pytań

 (0.2ms)  BEGIN
  SQL (67.6ms)  INSERT INTO "questions" ("city", "created_at", "province_id", "question_content", "question_details", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["city", "dd"], ["created_at", Tue, 14 May 2013 17:17:53 UTC +00:00], ["province_id", 3], ["question_content", "How's your car?"], ["question_details", "is it runnign"], ["updated_at", Tue, 14 May 2013 17:17:53 UTC +00:00], ["user_id", 12]]
   (31.9ms)  COMMIT

Chociaż nie przechowuję kategorii_kategorii w modelu Pytania, ustawiam kategorię_kategorii jako dopuszczalny parametr w kontrolerze pytań

   def question_params

      params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids)
    end

Czy ktoś może wyjaśnić, w jaki sposób mam zapisać category_ids? Uwaga: żadna akcja tworzenia nie istnieje w category_controller.rb żadnej z aplikacji.

Są to trzy tabele, które są takie same w obu aplikacjach

 create_table "questions", force: true do |t|
    t.text     "question_details"
    t.string   "question_content"
    t.integer  "user_id"
    t.integer  "accepted_answer_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "province_id"
    t.string   "city"
  end

 create_table "categories", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "categorizations", force: true do |t|
    t.integer  "category_id"
    t.integer  "question_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

Aktualizacja

To jest akcja tworzenia z aplikacji Rails 3

  def create
      @question = Question.new(params[:question])
      respond_to do |format|
      if @question.save
        format.html { redirect_to @question, notice: 'Question was successfully created.' }
        format.json { render json: @question, status: :created, location: @question }
      else
        format.html { render action: "new" }
        format.json { render json: @question.errors, status: :unprocessable_entity }
      end
    end
end

To jest akcja tworzenia z aplikacji Rails 4

   def create
      @question = Question.new(question_params)

       respond_to do |format|
      if @question.save
        format.html { redirect_to @question, notice: 'Question was successfully created.' }
        format.json { render json: @question, status: :created, location: @question }
      else
        format.html { render action: "new" }
        format.json { render json: @question.errors, status: :unprocessable_entity }
      end
    end
    end

To jest metoda question_params

 private
    def question_params 
      params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids)
    end
Leahcim
źródło
Jak wygląda akcja tworzenia w obu aplikacjach?
bennick
@bennick Dodałem dwie akcje tworzenia. Dzięki
Leahcim

Odpowiedzi:

527

Ta https://github.com/rails/strong_parameters wydaje się być odpowiednią sekcją dokumentów:

Dozwolone typy skalarne to String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch :: Http :: UploadedFile i Rack :: Test :: UploadedFile.

Aby zadeklarować, że wartość w params musi być tablicą dozwolonych wartości skalarnych, odwzoruj klucz na pustą tablicę:

params.permit(:id => [])

W mojej aplikacji category_ids są przekazywane do akcji create w tablicy

"category_ids"=>["", "2"],

Dlatego deklarując mocne parametry, jawnie ustawiłem kategorię_kategorii jako tablicę

params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids => [])

Działa idealnie teraz!

( WAŻNE: Jak zauważa @Lenart w komentarzach, deklaracje tablicowe muszą znajdować się na końcu listy atrybutów, w przeciwnym razie wystąpi błąd składniowy).

Leahcim
źródło
105
Zauważyłem również, że deklaracje tablic powinny znajdować się na końcu listy atrybutów. W przeciwnym razie pojawia się błąd składniowysyntax error, unexpected ')', expecting =>
Lenart,
45
Powodem deklaracji tablic (parametry zagnieżdżone) jest to, że ActionController :: Parameters.permit oczekuje, że każdy argument będzie skrótem lub symbolem. Ruby Magic zamieni wszystkie pary klucz-wartość na końcu wywołania metody w jeden skrót, ale Ruby nie będzie wiedziała, co zrobić, jeśli zmieszasz symbole z parami klucz / wartość w wywołaniu metody.
sameers
7
jeśli category_idsnie jest tablicą (np. wysłano ciąg znaków), wówczas szyny kompletnie oszalały i podnosi: ERROR TypeError: expected Array (got String) for param `category_ids'Czy to błąd w szynach? Edytuj: tak to jest: github.com/rails/rails/issues/11502
Dominik Goltermann
4
@Lenart Dzięki, myślałem, że wariuję. Powinno to przynajmniej pojawić się w strong_params README
Sebastialonso
3
@ Lenart możesz dodać go jako skrót, jeśli chcesz uniknąć błędu składniowego. params.permit(:foo, { bar: [] }, :zoo).
Zoo Foo Bar
99

Jeśli chcesz zezwolić na tablicę skrótów (lub an array of objectsz perspektywy JSON)

params.permit(:foo, array: [:key1, :key2])

2 punkty do zauważenia tutaj:

  1. arraypowinien być ostatnim argumentem permitmetody.
  2. powinieneś podać klucze skrótu w tablicy, w przeciwnym razie pojawi się błąd Unpermitted parameter: array, który w takim przypadku jest bardzo trudny do debugowania.
Brian
źródło
i tablice tablic nie są jeszcze obsługiwane ( github.com/rails/rails/issues/23640
Andrei Dziahel
11
arraynie musi znajdować się na końcu, ale musisz upewnić się, że masz prawidłowy Ruby. params.permit(:foo, array: [:key1, :key2], :bar)nie będzie poprawny ruby, ponieważ interpreter oczekuje klucza skrótu: pary wartości po pierwszym zestawie. Aby mieć ważny Rubin, potrzebujeszparams.permit(:foo, {array: [:key1, :key2]}, :bar)
mastaBlasta
Jesteś mistrzem!
Lollypop
22

Tak powinno być

params.permit(:id => [])

Również od wersji szyn 4+ możesz używać:

params.permit(id: [])
Matias Seguel
źródło
12
proszę nie, że tablica powinna być ostatnim argumentem metody zezwolenia
Matias Elorriaga,
3
Ta składnia skrótu, o której mówiłeś, że dotyczy Rails v4 +, jest w rzeczywistości składnią dostępną w Ruby 1.9 i nowszych, a nie w frameworku Rails (chociaż Rails 4 wymaga Ruby 1.9.3 lub nowszych)
MegaTux
11

Jeśli masz taką strukturę skrótu:

Parameters: {"link"=>{"title"=>"Something", "time_span"=>[{"start"=>"2017-05-06T16:00:00.000Z", "end"=>"2017-05-06T17:00:00.000Z"}]}}

W ten sposób mam to działać:

params.require(:link).permit(:title, time_span: [[:start, :end]])
Fellow Stranger
źródło
6

Nie mogę jeszcze komentować, ale postępując zgodnie z rozwiązaniem Fellow Stranger, możesz także zagnieżdżać się na wypadek, gdybyś miał klucze, których wartości są tablicą. Lubię to:

filters: [{ name: 'test name', values: ['test value 1', 'test value 2'] }]

To działa:

params.require(:model).permit(filters: [[:name, values: []]])
Daniel Duque
źródło