Rails 4.0 Strong Parameters zagnieżdżone atrybuty z kluczem wskazującym na hash
Bawiłem się Rails 4.X beta i próbuje uzyskać zagnieżdżone atrybuty współpracujące z carrierwave. Nie jestem pewien, czy to, co robię, jest dobrym kierunkiem. Po przeszukaniu wokół, a następnie w końcu patrząc na źródło rails i silne parametry znalazłem poniższe notatki.
# Note that if you use +permit+ in a key that points to a hash, # it won't allow all the hash. You also need to specify which # attributes inside the hash should be whitelisted.
Więc mówi, że musisz określić każdy pojedynczy atrybut w has, próbowałem następujących:
Przykład Parama:
{"utf8"=>"✓",
"authenticity_token"=>"Tm54+v9DYdBtWJ7qPERWzdEBkWnDQfuAQrfT9UE8VD=",
"screenshot"=>{
"title"=>"afs",
"assets_attributes"=>{
"0"=>{
"filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40
@tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>,
@original_filename="EK000005.JPG",
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n">
}
}
},
"commit"=>"Create Screenshot"}
Controller
def screenshot_params
params.require(:screenshot).permit(:title,
:assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers]
Powyższe nie działa (nie uruchamia carrierwave), jednak nie dostaję już błędów (nieprzepisowe parametry: nazwa pliku) przy użyciu standardowych zagnieżdżonych przykładów, które znalazłem np:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
Gdyby ktoś mógł pomóc, byłoby świetnie. Nie udało mi się znaleźć przykładu z zagnieżdżonym kluczem, który wskazuje na hash. 6 answers
Moja druga odpowiedź była w większości błędna-Nowa odpowiedź.
W Twoim parametrze hash: filename nie jest skojarzony z innym Hashem, jest powiązany z obiektem Activedispatch::Http:: UploadedFile. Ostatnia linia kodu:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
Jest poprawne, jednak atrybut filename nie jest dozwolony, ponieważ nie jest jednym z dozwolonych typów skalarnych . Jeśli otworzysz konsolę i zainicjalizujesz obiekt params w tym kształcie:
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}}
A następnie uruchom go przeciwko swojej ostatni wiersz:
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
Jeśli jednak zrobisz to samo z hashiem params z przesłanym plikiem, otrzymasz
upload = ActionDispatch::Http::UplaodedFile.new tempfile: StringIO.new("abc"), filename: "abc"
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: upload}}}
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{}}}
Więc, prawdopodobnie warto zrobić bug lub pull request Do Rails, a w międzyczasie, będziesz musiał bezpośrednio uzyskać dostęp do parametru filename używając raw params
object:
params[:screenshot][:assets_attributes]["0"][:filename]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-23 18:31:51
Więc masz do czynienia z has_many formularzy i silnych parametrów.
To jest ta część params hash, która się liczy:
"assets_attributes"=>{
"0"=>{
"filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40
@tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>,
@original_filename="EK000005.JPG",
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n">
}
}
Kiedy zdefiniujesz takie silne parametry...
permit(:assets_attributes => [:filename])
Rzeczy się psują, bo tam, gdzie rails oczekuje filename
to dostaje to "0"
id
dla aktywów, które przesyłasz za pośrednictwem formularza. Teraz początkowo możesz pomyśleć, że musisz zrobić coś w stylu
permit(:assets_attributes => [:id => [:filename]])
To wygląda tak podąża za innymi silnymi konwencjami składni parametrów. Jednak, na dobre i na złe, sprawili, że wszystko było trochę łatwiejsze, a wszystko, co musisz napisać, to:
permit(:assets_attributes => [:asset_id, :filename])
Edit - Jak jpwynn zauważył w komentarzach, w Rails 4.2.4 + poprawna składnia to
permit(:assets_attributes => [:id, :filename])
I to powinno zadziałać.
Kiedy uderzasz w ściany silnymi paramami, najlepszą rzeczą do zrobienia jest wrzucenie debuggera do kontrolera i przetestowanie wszystkiego. params.require(:something).permit(:other_things)
jest tylko łańcuchem metod, więc można Wypróbuj różne rzeczy na pełnym hash params, aż znajdziesz to, co działa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:38
Try
def screenshot_params
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
end
Miałem ten problem około miesiąc temu i niektóre poszukiwania wokół wykopali To rozwiązanie. To było dodanie :id lub: screenshot_id, które naprawiło problem(lub obu, nie pamiętam). To działa w moim kodzie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-17 09:09:32
W rzeczywistości istnieje sposób na białą listę wszystkich zagnieżdżonych parametrów.
params.require(:screenshot).permit(:title).tap do |whitelisted|
whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ]
end
Metoda ta ma przewagę nad innymi rozwiązaniami. pozwala zezwolić na głębokie zagnieżdżanie parametrów.
Podczas gdy inne rozwiązania jak:
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
Nie.]}
Źródło:
Https://github.com/rails/rails/issues/9454#issuecomment-14167664
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 21:00:03
Miałem ten sam problem tylko go naprawiłem teraz wszystko co musisz zrobić to
params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]).
Użyj pry gem, aby zobaczyć, jakiego rodzaju atrybuty posiada obiekt zasobu, aby upewnić się, że istnieje identyfikator i dodać inny brakujący atrybut, który powinien działać idealnie. Używam zasobów paperclip to mój zagnieżdżony obiekt wewnątrz klasy pojazdu, a załącznik obrazów jest dodawany do zasobu. upewnij się, że wykonasz walidację w modelu
accepts_nested_attributes_for :assets, allow_destroy: true
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
W pętli widoku przez zasób, aby uzyskać każdy obraz
<%= @vehicle.assets.size %>
<% for asset in @vehicle.assets %>
<%=link_to image_tag (asset.image.url(:thumb)) %>
<% end %>
Jeśli poprawię twój problem polega na tym, że asset_attributes jest tablicą z każdym obrazem mającym kolumnę indeksu i obraz
Twój formula_for powinien mieć coś podobnego do tego, a jeśli chcesz, możesz również dołączyć Podgląd, aby upload mógł wyświetlać swoje obrazy, użyj dolnego kodu do tego
<div class="field">
<h3>Vehicle Image Upload</h3>
<%= f.fields_for :assets do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<p>
<%= asset_fields.file_field :image %>
</p>
<% end %>
<% end %>
</div>
<div class="field">
<h4>Vehicle Image</h4>
<%= f.fields_for :assets do |asset_fields| %>
<% unless asset_fields.object.new_record? %>
<%= link_to image_tag(asset_fields.object.image.url(:thumb)),
asset_fields.object.image.url(:original)%>
<%= asset_fields.check_box :_destroy %>
<% end %>
<% end %>
</div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-04 17:50:22
Sanitize przed zapisaniem w kontrolerze Sanitize accepts_nested_attributes_for atrybuty z indeksem.
before_action :sanitize_fields_params, :only => [:create, :update]
def sanitize_fields_params
product_free_shippings_attributes = params[:product][:product_free_shippings_attributes]
product_free_shippings_attributes.each do |index, key_value|
params[:product][:product_free_shippings_attributes]["#{index}"][:weight] = clear_decimal(key_value[:weight])
params[:product][:product_free_shippings_attributes]["#{index}"][:height] = clear_decimal(key_value[:height])
params[:product][:product_free_shippings_attributes]["#{index}"][:width] = clear_decimal(key_value[:width])
params[:product][:product_free_shippings_attributes]["#{index}"][:depth] = clear_decimal(key_value[:depth])
end
end
def clear_decimal(field)
return (field.to_s.gsub(/[^\d]/, '').to_d / 100.to_d) unless field.blank?
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-02 14:03:23