#1 Od: 00bd00, August 16th, 2015 15:27
Zdravím,
budu tu mít pár začátečnických dotazů, co mi není jasný a který vyvstanuly ve chvíli, kdy jsem začal opravdu psát.
Mám jednu aplikaci, kvůli které jsem se rozhodl naučit RoR (sice bych to v .NETu měl asi za čtvrtinu času, ale to neva), a chtěl bych se zeptat na tohle:
pokud použiju form_for, můžu to použít i pro formulář, kde
nenaplním všechny pole modelu (třeba @user má name, email a password
a já ve formuláři mám jenom f.email a f.password)?
Jak mám validovat model (dejme tomu třeba opět User), kdy při registraci chci vyplnit jen email a heslo (tedy tyto dvě pole jsou povinné, jako jediné), ale následně po registraci, při vyplňování profilu chci mít povinné i pole Name?
Co musím udělat pro to, aby se mi do formuláře zobrazily chyby z
@user.errors?
-
Jak jsem pochopil, v controlleru musím nastavit, která pole mohu
plnit z formuláře (strong properties). Čili to vypadá takto:
def new
@user = User.new(user_params)
end
private
def user_params
params.require(:user).permit(:email, : password, : password_confirmation)
end
Nicméně dostanu chybu, že :user je nil (param is missing or the value is empty: user), žemuž tedy vůbec nerozumím.
Děkuji 
#2 Od: xHire, August 17th, 2015 03:01
Ahoj,
jdeš na to dobře.
ad 1. Ano, můžeš.
ad 2. Můžeš využít parametrů :if
/:unless
, kterým můžeš předat proc
, ve kterém ověříš, jestli jde o nový nebo starý záznam, například:
validates :name, :presence => true, :length => { :maximum => 64 }, :unless => proc {|user| user.new_record? }
ad 3. Vypsat si je. :c) Takový kód může vypadat například takto:
<%- if @user.errors.any? -%>
<div id="error_explanation">
<h3>Při kontrole správnosti vyplněných údajů byly zjištěny tyto nedostatky:</h3>
<ul>
<%- @user.errors.full_messages.each do |msg| -%>
<li><%= msg %></li>
<%- end -%>
</ul>
</div>
<%- end -%>
ad 4. Přesně tak. Je to ochrana proti tomu, aby ti někdo podvrhnul nějaká svá data do formuláře. Vzpomínám si například, jak tohle prováděli například s atributy created_at
.
(Nicméně podcenění téhle slabiny vedlo až na získání správcovských práv nad repozitářem Railsů na GitHubu). Jo, ta chyba – zkus sem vložit, jak vypadá obsah params
. Tipuju to na problém ve formuláři, i když z těch střípků to tak zatím moc nevypadá.
#3 Od: Josef Šimánek, August 17th, 2015 05:35
Bod 2: Tohle se dá řešit ještě trochu elegantněji.
Buď můžeš použít with_options blok, cca takhle:
with_options if: :persisted? do
validates :name, presence: true
end
Nebo použít on
:
validates :name , presence: true, on: :update
Pak jsem ještě někde zahlédl, že se dá použít on
a vlastní context, ale sám jsem to nikdy nepoužil.
#4 Od: 00bd00, August 18th, 2015 06:41
Díky za odpověď, oboum.
K tomu bodu 4:
params[:user] je nil.
Formulář vypadá takto:
<%= form_for @user do |f| %>
<div class="form-item">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="form-item">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="form-item">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="form-actions">
<%= f.submit "Register" %>
</div>
<% end %>
I controlleru v metodě Create je params[:user] nil:
class UsersController < ApplicationController
def new
@user = User.new(user_params)
end
def create
@user = User.new(params[:user])
if @user.save
redirect_to root_url, :notice => 'Thank you for the registration!'
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Routes.rb vypadají takto:
root 'home#index'
match '/login', to: 'sessions#new', via: 'get'
match '/register', to: 'users#new', via: 'get'
match '/logout', to: 'sessions#destroy', via: 'get'
resources :users
resources :sessions
Nemůže to nějak souviset s atributem password_confirmation ve třídě User? On to vlastně není sloupec v tabulce..
Díky
#5 Od: xHire, August 18th, 2015 14:33
Aha, já si nevšiml, že to padá v akci new
.
V téhle akci volej jen
@user = User.new
Naproti tomu v akci create
používáš tu nebezpečnou variantu – tady bys měl mít ten původní řádek z akce new
.
Atribut password_confirmation
je virtuální – potřebné metody k němu dodává gem, který používáš (authlogic/sorcery/devise/...), takže ten je v pořádku.
#6 Od: 00bd00, August 18th, 2015 16:40
Ty vogo, funguje to
Sice nechápu jak - resp. jsem měl za to, že v metodě create
musím předat do User.new
právě params
. Ale to asi nemusím, protože jsem použil form_for @user
, říkám to správně? Moc magie najednou 
A pro autentifikaci nepoužívám žádný gem, jako správný začátečník podle všech rad si první píšu sám.
Každopádně dík
#7 Od: 00bd00, August 21st, 2015 04:14
Zdravím,
měl bych další dotaz. V souboru page.coffee mám autocomplete, který mi funguje, ale potřeboval bych tam přidat další parametr (data z autocomplete chci filtrovat ještě na základě vybrané položky v comboboxu):
jQuery ->
$('#search').autocomplete
source: '/autocomplete_source',
data:
key: 'value'
Nicméně v controlleru v params
to nemám. Jak jsem schopný tyto data
získat?
Díky
Systém běží na Discourse, nejlepší zážitek je se zapnutým JavaScriptem