PASTABA: Šis vadovas nėra skirtas visiems galimiems formos pagalbininkams ir jų argumentams išsamiai aprašyti. Visų galimų pagalbinių priemonių išsamiam aprašymui apsilankykite Rails API dokumentacijoje.
1 Darbas su pagrindinėmis formomis
Pagrindinė formos pagalbininkė yra form_with
.
<%= form_with do |form| %>
Formos turinys
<% end %>
Kai jis yra iškviestas be argumentų, kaip šiuo atveju, jis sukuria formos žymą, kurią pateikus ji bus išsiųsta į dabartinį puslapį. Pavyzdžiui, jei dabartinis puslapis yra pagrindinis puslapis, sugeneruotas HTML atrodo taip:
<form accept-charset="UTF-8" action="/" method="post">
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
Formos turinys
</form>
Pastebėsite, kad HTML yra input
elementas su tipo hidden
. Šis input
yra svarbus, nes ne-GET formos negali būti sėkmingai išsiųstos be jo.
Paslėptas įvesties elementas su pavadinimu authenticity_token
yra "Rails" saugumo funkcija, vadinama cross-site request forgery protection (apsaugą nuo kryžminio svetainių užklausų sukčiavimo), ir formos pagalbininkai jį generuoja kiekvienai ne-GET formai (jei ši saugumo funkcija yra įjungta). Apie tai galite sužinoti daugiau Saugių "Rails" aplikacijų vadove.
1.1 Bendrosios paieškos forma
Viena iš paprasčiausių internete matomų formų yra paieškos forma. Ši forma apima:
- formos elementą su "GET" metodu,
- etiketę įvesties laukui,
- teksto įvesties elementą ir
- pateikimo elementą.
Norėdami sukurti šią formą, naudosime form_with
ir formos kūrėjo objektą, kurį jis grąžina. Taip:
<%= form_with url: "/search", method: :get do |form| %>
<%= form.label :query, "Ieškoti:" %>
<%= form.text_field :query %>
<%= form.submit "Ieškoti" %>
<% end %>
Tai sugeneruos šį HTML:
<form action="/search" method="get" accept-charset="UTF-8" >
<label for="query">Ieškoti:</label>
<input id="query" name="query" type="text" />
<input name="commit" type="submit" value="Ieškoti" data-disable-with="Ieškoti" />
</form>
PATARIMAS: Pervadindami url: mano_nurodytas_kelias
į form_with
pasakote formai, kur išsiųsti užklausą. Tačiau, kaip paaiškinama žemiau, formai taip pat galite perduoti "Active Record" objektus.
PATARIMAS: Kiekvienai formos įvesties reikšmei yra sugeneruojamas ID atributas iš jos pavadinimo ("query"
pavyzdžiuose aukščiau). Šie ID gali būti labai naudingi CSS stiliui ar formos valdiklių manipuliavimui su JavaScript.
SVARBU: Paieškos formoms naudokite "GET" kaip metodą. Tai leidžia naudotojams įrašyti konkretų paieškos rezultatą ir grįžti prie jo. Iš esmės "Rails" skatina naudoti tinkamą HTTP veiksmo veiksmą.
1.2 Pagalbininkai formos elementams generuoti
form_with
grąžinamas formos kūrėjo objektas teikia daugybę pagalbinių metodų, skirtų generuoti formos elementus, tokius kaip teksto laukai, žymimieji langeliai ir radijo mygtukai. Pirmasis parametras šiems metodams visada yra įvesties pavadinimas. Kai forma yra pateikiama, pavadinimas bus perduotas kartu su forma duomenimis ir pasieks params
kontroleryje su naudotojo įvesta reikšme šiam laukui. Pavyzdžiui, jei formoje yra <%= form.text_field :query %>
, tuomet galėsite gauti šio lauko reikšmę kontroleryje su params[:query]
.
Kai pavadinate įvestis, „Rails“ naudoja tam tikras konvencijas, kurios leidžia pateikti parametrus su ne skalinių reikšmių, pvz., masyvų arba žodynų, kurie taip pat bus pasiekiami „params“. Apie juos galite sužinoti daugiau Suprantant parametrų pavadinimo konvencijas šio vadovo skyriuje. Išsamesnė informacija apie šių pagalbininkų tikslų naudojimą pateikta API dokumentacijoje.
1.2.1 Žymimieji langeliai
Žymimieji langeliai yra formos valdikliai, kurie leidžia vartotojui pasirinkti arba išjungti rinkinį parinkčių:
<%= form.check_box :pet_dog %>
<%= form.label :pet_dog, "Aš turiu šunį" %>
<%= form.check_box :pet_cat %>
<%= form.label :pet_cat, "Aš turiu katę" %>
Tai generuoja šį rezultatą:
<input type="checkbox" id="pet_dog" name="pet_dog" value="1" />
<label for="pet_dog">Aš turiu šunį</label>
<input type="checkbox" id="pet_cat" name="pet_cat" value="1" />
<label for="pet_cat">Aš turiu katę</label>
Pirmasis parametras check_box
yra įvesties pavadinimas. Žymimųjų langelių reikšmės (reikšmės, kurios bus prieinamos „params“) gali būti nurodytos naudojant trečiąjį ir ketvirtąjį parametrus. Išsamesnę informaciją rasite API dokumentacijoje.
1.2.2 Radijo mygtukai
Radijo mygtukai, nors ir panašūs į žymimuosius langelius, yra valdikliai, kurie nurodo rinkinį parinkčių, kurios yra tarpusavyje išskiriamos (t. y. vartotojas gali pasirinkti tik vieną):
<%= form.radio_button :age, "child" %>
<%= form.label :age_child, "Aš esu jaunesnis nei 21" %>
<%= form.radio_button :age, "adult" %>
<%= form.label :age_adult, "Aš esu vyresnis nei 21" %>
Rezultatas:
<input type="radio" id="age_child" name="age" value="child" />
<label for="age_child">Aš esu jaunesnis nei 21</label>
<input type="radio" id="age_adult" name="age" value="adult" />
<label for="age_adult">Aš esu vyresnis nei 21</label>
Antrasis parametras radio_button
yra įvesties reikšmė. Kadangi šie du radijo mygtukai bendrai naudoja tą patį pavadinimą (age
), vartotojas galės pasirinkti tik vieną iš jų, o params[:age]
bus "child"
arba "adult"
.
PASTABA: Visada naudokite žymes žymimiesiems langeliams ir radijo mygtukams. Jos sieja tekstą su konkretesne parinktimi ir, išplečiant paspaudimo sritį, palengvina vartotojams paspausti įvestis.
1.3 Kiti naudingi pagalbininkai
Kiti verti paminėjimo formos valdikliai yra teksto srities, paslėptosios srities, slaptažodžio srities, skaičiaus srities, datos ir laiko srities ir daugelis kitų:
<%= form.text_area :message, size: "70x5" %>
<%= form.hidden_field :parent_id, value: "foo" %>
<%= form.password_field :password %>
<%= form.number_field :price, in: 1.0..20.0, step: 0.5 %>
<%= form.range_field :discount, in: 1..100 %>
<%= form.date_field :born_on %>
<%= form.time_field :started_at %>
<%= form.datetime_local_field :graduation_day %>
<%= form.month_field :birthday_month %>
<%= form.week_field :birthday_week %>
<%= form.search_field :name %>
<%= form.email_field :address %>
<%= form.telephone_field :phone %>
<%= form.url_field :homepage %>
<%= form.color_field :favorite_color %>
Rezultatas:
<textarea name="message" id="message" cols="70" rows="5"></textarea>
<input type="hidden" name="parent_id" id="parent_id" value="foo" />
<input type="password" name="password" id="password" />
<input type="number" name="price" id="price" step="0.5" min="1.0" max="20.0" />
<input type="range" name="discount" id="discount" min="1" max="100" />
<input type="date" name="born_on" id="born_on" />
<input type="time" name="started_at" id="started_at" />
<input type="datetime-local" name="graduation_day" id="graduation_day" />
<input type="month" name="birthday_month" id="birthday_month" />
<input type="week" name="birthday_week" id="birthday_week" />
<input type="search" name="name" id="name" />
<input type="email" name="address" id="address" />
<input type="tel" name="phone" id="phone" />
<input type="url" name="homepage" id="homepage" />
<input type="color" name="favorite_color" id="favorite_color" value="#000000" />
Paslėptosios srities įvestys nėra rodomos vartotojui, bet vietoj to laiko duomenis kaip bet kuri tekstinė įvestis. Juose esančios reikšmės gali būti keičiamos naudojant „JavaScript“.
Svarbu: Paieškos, telefono, datos, laiko, spalvos, datos ir laiko, mėnesio, savaitės, URL, el. pašto, skaičiaus ir intervalo įvestys yra HTML5 valdikliai. Jei norite, kad jūsų programa turėtų nuoseklią patirtį senesniuose naršyklėse, jums reikės HTML5 polifilo (teikiamo CSS ir/arba JavaScript). Tikrai nėra trūkumo sprendimų šiai problemai spręsti, nors šiuo metu populiarus įrankis yra Modernizr, kuris suteikia paprastą būdą pridėti funkcionalumą pagal aptiktas HTML5 funkcijas. Patarimas: Jei naudojate slaptažodžio įvedimo laukus (bet kokiu tikslu), galbūt norėsite sukonfigūruoti savo programą, kad šie parametrai nebūtų įrašomi į žurnalą. Apie tai galite sužinoti Securing Rails Applications vadove.
2 Dirbant su modelio objektais
2.1 Formos susiejimas su objektu
form_with
metodo :model
argumentas leidžia susieti formos kūrėjo objektą su modelio objektu. Tai reiškia, kad forma bus apribota šiuo modelio objektu, o formos laukai bus užpildyti reikšmėmis iš šio modelio objekto.
Pavyzdžiui, jei turime @article
modelio objektą:
@article = Article.find(42)
# => #<Article id: 42, title: "My Title", body: "My Body">
Tokia forma:
<%= form_with model: @article do |form| %>
<%= form.text_field :title %>
<%= form.text_area :body, size: "60x10" %>
<%= form.submit %>
<% end %>
Generuos:
<form action="/articles/42" method="post" accept-charset="UTF-8" >
<input name="authenticity_token" type="hidden" value="..." />
<input type="text" name="article[title]" id="article_title" value="My Title" />
<textarea name="article[body]" id="article_body" cols="60" rows="10">
My Body
</textarea>
<input type="submit" name="commit" value="Update Article" data-disable-with="Update Article">
</form>
Čia yra keletas dalykų, kuriuos reikia pastebėti:
- Formos
action
automatiškai užpildoma tinkama@article
reikšme. - Formos laukai automatiškai užpildomi atitinkamomis reikšmėmis iš
@article
. - Formos laukų pavadinimai apriboti su
article[...]
. Tai reiškia, kadparams[:article]
bus maišas, kuriame bus visų šių laukų reikšmės. Daugiau apie įvesties pavadinimų svarbą galite paskaityti šio vadovo Understanding Parameter Naming Conventions skyriuje. - Pateikimo mygtukui automatiškai priskiriama tinkama teksto reikšmė.
Patarimas: Paprastai jūsų įvestys atitiks modelio atributus. Tačiau tai nėra būtina! Jei turite kitos informacijos, kurią reikia, galite ją įtraukti į formą, kaip ir atributus, ir pasiekti ją per params[:article][:my_nifty_non_attribute_input]
.
2.1.1 fields_for
pagalbininkas
fields_for
pagalbininkas sukuria panašų susiejimą, bet be <form>
žymės generavimo. Tai gali būti naudojama generuoti laukus papildomiems modelio objektams toje pačioje formoje. Pavyzdžiui, jei turite Person
modelį su susijusiu ContactDetail
modeliu, galite sukurti vieną formą abiem taip:
<%= form_with model: @person do |person_form| %>
<%= person_form.text_field :name %>
<%= fields_for :contact_detail, @person.contact_detail do |contact_detail_form| %>
<%= contact_detail_form.text_field :phone_number %>
<% end %>
<% end %>
Tai generuos šį rezultatą:
<form action="/people" accept-charset="UTF-8" method="post">
<input type="hidden" name="authenticity_token" value="bL13x72pldyDD8bgtkjKQakJCpd4A8JdXGbfksxBDHdf1uC0kCMqe2tvVdUYfidJt0fj3ihC4NxiVHv8GVYxJA==" />
<input type="text" name="person[name]" id="person_name" />
<input type="text" name="contact_detail[phone_number]" id="contact_detail_phone_number" />
</form>
fields_for
grąžinamas objektas yra formos kūrėjas, panašus į form_with
grąžinamą objektą.
2.2 Remiantis įrašo identifikacija
Straipsnio modelis yra tiesiogiai prieinamas programos naudotojams, todėl, vadovaujantis geriausiomis Rails kūrimo praktikomis, jį turėtumėte paskelbti resursu:
resources :articles
Patarimas: Resurso paskelbimas turi keletą šalutinių pasekmių. Daugiau informacijos apie resursų nustatymą ir naudojimą galite rasti Rails Routing from the Outside In vadove.
Dirbant su RESTful resursais, naudojant įrašo identifikaciją, form_with
kvietimai gali būti žymiai paprastesni. Trumpai tariant, galite tiesiog perduoti modelio egzempliorių ir leisti Rails nustatyti modelio pavadinimą ir kitus parametrus. Šiuose dviejuose pavyzdžiuose ilgas ir trumpas stilius turi tą patį rezultatą:
## Naujo straipsnio kūrimas
# ilgas stilius:
form_with(model: @article, url: articles_path)
# trumpas stilius:
form_with(model: @article)
## Esamo straipsnio redagavimas
# ilgas stilius:
form_with(model: @article, url: article_path(@article), method: "patch")
# trumpas stilius:
form_with(model: @article)
Pastebėkite, kaip trumpojo stiliaus form_with
kvietimas yra patogus ir tas pats, nepriklausomai nuo to, ar įrašas yra naujas, ar jau egzistuoja. Įrašo identifikacija pakankamai protinga, kad nustatytų, ar įrašas yra naujas, klausdamas record.persisted?
. Ji taip pat pasirenka teisingą maršrutą pateikimui ir pavadinimą pagal objekto klasę.
Jei turite vienintelį išteklių, jums reikės paskambinti resource
ir resolve
, kad jis veiktų su form_with
:
resource :geocoder
resolve('Geocoder') { [:geocoder] }
ĮSPĖJIMAS: Kai naudojate STI (vienintelės lentelės paveldėjimą) su savo modeliais, negalite pasikliauti įrašo identifikacija po klasės, jei tik jų tėvų klasė yra deklaruota kaip išteklius. Turėsite nurodyti :url
ir :scope
(modelio pavadinimą) aiškiai.
2.2.1 Susidūrimas su vardų erdvėmis
Jei sukūrėte vardų erdvės maršrutus, form_with
taip pat turi patogų trumpinį. Jei jūsų programoje yra administratoriaus vardų erdvė, tada
form_with model: [:admin, @article]
sukurs formą, kurią pateikia ArticlesController
viduje admin vardų erdvės (pateikiant admin_article_path(@article)
atnaujinimo atveju). Jei turite kelias vardų erdves, sintaksė yra panaši:
form_with model: [:admin, :management, @article]
Daugiau informacijos apie „Rails“ maršrutizavimo sistemą ir susijusias konvencijas rasite „Rails Routing from the Outside In“ vadove.
2.3 Kaip veikia formos su PATCH, PUT arba DELETE metodais?
„Rails“ karkasas skatina jūsų programų RESTful projektavimą, tai reiškia, kad be „GET“ ir „POST“ užklausų, daugiausia naudosite „PATCH“, „PUT“ ir „DELETE“ užklausas. Tačiau dauguma naršyklių nepalaiko kitų nei „GET“ ir „POST“ metodų naudojimo formų pateikimo.
„Rails“ šią problemą sprendžia imituodamas kitus metodus per POST su paslėptu įvesties lauku, kurio pavadinimas yra "_method"
, kuris nustatomas atitinkamai:
form_with(url: search_path, method: "patch")
Išvestis:
<form accept-charset="UTF-8" action="/search" method="post">
<input name="_method" type="hidden" value="patch" />
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
<!-- ... -->
</form>
Analizuojant pateiktus duomenis, „Rails“ atsižvelgs į specialųjį _method
parametrą ir elgsis taip, tarsi HTTP metodas būtų tas, kuris nurodytas jame (šiuo pavyzdžiu - „PATCH“).
Rodydami formą, pateikimo mygtukai gali perrašyti nurodytą method
atributą naudojant formmethod:
raktažodį:
<%= form_with url: "/posts/1", method: :patch do |form| %>
<%= form.button "Delete", formmethod: :delete, data: { confirm: "Are you sure?" } %>
<%= form.button "Update" %>
<% end %>
Panašiai kaip <form>
elementai, dauguma naršyklių nepalaiko formos metodų perrašymo, nurodytų per formmethod kitais nei „GET“ ir „POST“ metodais.
„Rails“ šią problemą sprendžia imituodamas kitus metodus per POST, naudodamas formmethod, value ir name atributų kombinaciją:
<form accept-charset="UTF-8" action="/posts/1" method="post">
<input name="_method" type="hidden" value="patch" />
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
<!-- ... -->
<button type="submit" formmethod="post" name="_method" value="delete" data-confirm="Are you sure?">Delete</button>
<button type="submit" name="button">Update</button>
</form>
3 Lengvai kuriamos pasirinkimo laukai
HTML pasirinkimo laukams reikalingas didelis žymėjimas - vienas <option>
elementas kiekvienai galimybei pasirinkti. Todėl „Rails“ teikia pagalbines funkcijas, kurios sumažina šį naštą.
Pavyzdžiui, sakykime, turime sąrašą miestų, iš kurio vartotojas gali pasirinkti. Galime naudoti select
pagalbininką taip:
<%= form.select :city, ["Berlin", "Chicago", "Madrid"] %>
Išvestis:
<select name="city" id="city">
<option value="Berlin">Berlin</option>
<option value="Chicago">Chicago</option>
<option value="Madrid">Madrid</option>
</select>
Taip pat galime nurodyti <option>
reikšmes, kurios skiriasi nuo jų žymėjimo:
<%= form.select :city, [["Berlin", "BE"], ["Chicago", "CHI"], ["Madrid", "MD"]] %>
Išvestis:
<select name="city" id="city">
<option value="BE">Berlin</option>
<option value="CHI">Chicago</option>
<option value="MD">Madrid</option>
</select>
Taip vartotojas matys pilną miesto pavadinimą, bet params[:city]
bus viena iš "BE"
, "CHI"
arba "MD"
.
Galiausiai galime nurodyti numatytąjį pasirinkimą pasirinkimo laukui naudodami :selected
argumentą:
<%= form.select :city, [["Berlin", "BE"], ["Chicago", "CHI"], ["Madrid", "MD"]], selected: "CHI" %>
Išvestis:
<select name="city" id="city">
<option value="BE">Berlin</option>
<option value="CHI" selected="selected">Chicago</option>
<option value="MD">Madrid</option>
</select>
3.1 Pasirinkimo grupės
Kai kuriais atvejais norime pagerinti vartotojo patirtį, grupuodami susijusias galimybes. Tai galime padaryti perduodami Hash
(arba palyginamą Array
) į select
:
erb
<%= form.select :city,
{
"Europa" => [ ["Berlynas", "BE"], ["Madridas", "MD"] ],
"Šiaurės Amerika" => [ ["Čikaga", "CHI"] ],
},
selected: "CHI" %>
Rezultatas:
<select name="city" id="city">
<optgroup label="Europa">
<option value="BE">Berlynas</option>
<option value="MD">Madridas</option>
</optgroup>
<optgroup label="Šiaurės Amerika">
<option value="CHI" selected="selected">Čikaga</option>
</optgroup>
</select>
3.2 Pasirinkimo laukai ir modelio objektai
Kaip ir kiti formos valdikliai, pasirinkimo lauką galima susieti su modelio atributu. Pavyzdžiui, jei turime @person
modelio objektą:
@person = Person.new(city: "MD")
Ši forma:
<%= form_with model: @person do |form| %>
<%= form.select :city, [["Berlynas", "BE"], ["Čikaga", "CHI"], ["Madridas", "MD"]] %>
<% end %>
Išveda pasirinkimo lauką:
<select name="person[city]" id="person_city">
<option value="BE">Berlynas</option>
<option value="CHI">Čikaga</option>
<option value="MD" selected="selected">Madridas</option>
</select>
Pastebėkite, kad tinkama parinktis automatiškai pažymėta selected="selected"
. Kadangi šis pasirinkimo laukas buvo susietas su modeliu, nereikėjo nurodyti :selected
argumento!
3.3 Laiko juosta ir šalies pasirinkimas
Norint pasinaudoti laiko juostos palaikymu „Rails“, reikia paklausti vartotojų, kuriame laiko juostoje jie yra. Tai reikalauja sugeneruoti pasirinkimo galimybes iš iš anksto apibrėžtų ActiveSupport::TimeZone
objektų sąrašo, tačiau galite tiesiog naudoti time_zone_select
pagalbininką, kuris tai jau apgaubia:
<%= form.time_zone_select :time_zone %>
„Rails“ anksčiau turėjo country_select
pagalbininką, skirtą šalių pasirinkimui, tačiau jis buvo išskirtas į country_select įskiepį.
4 Naudojant datos ir laiko formos pagalbinius elementus
Jei nenorite naudoti HTML5 datos ir laiko įvesties, „Rails“ teikia alternatyvius datos ir laiko formos pagalbinius elementus, kurie atvaizduoja paprastus pasirinkimo laukus. Šie pagalbiniai elementai atvaizduoja pasirinkimo lauką kiekvienam laiko komponentui (pvz., metai, mėnuo, diena ir kt.). Pavyzdžiui, jei turime @person
modelio objektą:
@person = Person.new(birth_date: Date.new(1995, 12, 21))
Ši forma:
<%= form_with model: @person do |form| %>
<%= form.date_select :birth_date %>
<% end %>
Išveda pasirinkimo laukus:
<select name="person[birth_date(1i)]" id="person_birth_date_1i">
<option value="1990">1990</option>
<option value="1991">1991</option>
<option value="1992">1992</option>
<option value="1993">1993</option>
<option value="1994">1994</option>
<option value="1995" selected="selected">1995</option>
<option value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
<option value="1999">1999</option>
<option value="2000">2000</option>
</select>
<select name="person[birth_date(2i)]" id="person_birth_date_2i">
<option value="1">Sausis</option>
<option value="2">Vasaris</option>
<option value="3">Kovas</option>
<option value="4">Balandis</option>
<option value="5">Gegužė</option>
<option value="6">Birželis</option>
<option value="7">Liepa</option>
<option value="8">Rugpjūtis</option>
<option value="9">Rugsėjis</option>
<option value="10">Spalis</option>
<option value="11">Lapkritis</option>
<option value="12" selected="selected">Gruodis</option>
</select>
<select name="person[birth_date(3i)]" id="person_birth_date_3i">
<option value="1">1</option>
...
<option value="21" selected="selected">21</option>
...
<option value="31">31</option>
</select>
Pastebėkite, kad pateikiant formą, params
maiše nebus vieno vertės, kurią sudarytų visas datos laukas. Vietoj to, bus keletas vertės su specialiais pavadinimais, pvz., "birth_date(1i)"
. „Active Record“ žino, kaip sudėti šiuos specialiai pavadintus laukus į visą datą ar laiką, remiantis modelio atributo deklaruota tipu. Taigi galime perduoti params[:person]
į Person.new
arba Person#update
, kaip ir darytume, jei forma naudotų vieną lauką, kuris atstovautų visai datai.
Be date_select
pagalbininko, „Rails“ teikia time_select
ir datetime_select
.
4.1 Pasirinkimo laukai atskiriems laiko komponentams
„Rails“ taip pat teikia pagalbinius elementus, skirtus atskiriems laiko komponentams atvaizduoti: select_year
, select_month
, select_day
, select_hour
, select_minute
ir select_second
. Šie pagalbiniai elementai yra „nuogi“ metodai, tai reiškia, kad jie nėra iškviesti ant formos kūrėjo objekto. Pavyzdžiui:
<%= select_year 1999, prefix: "party" %>
Išveda pasirinkimo lauką:
<select name="party[year]" id="party_year">
<option value="1994">1994</option>
<option value="1995">1995</option>
<option value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
<option value="1999" selected="selected">1999</option>
<option value="2000">2000</option>
<option value="2001">2001</option>
<option value="2002">2002</option>
<option value="2003">2003</option>
<option value="2004">2004</option>
</select>
Kiekvienam iš šių pagalbinių elementų galite nurodyti datą ar laiko objektą kaip numatytąją vertę, o tinkamas laiko komponentas bus išskirtas ir naudojamas.
5 Pasirinkimas iš bet kokių objektų kolekcijos
Kartais norime sugeneruoti pasirinkimų rinkinį iš bet kokių objektų kolekcijos. Pavyzdžiui, jei turime City
modelį ir atitinkamą belongs_to :city
asociaciją:
class City < ApplicationRecord
end
class Person < ApplicationRecord
belongs_to :city
end
City.order(:name).map { |city| [city.name, city.id] }
# => [["Berlinas", 3], ["Čikaga", 1], ["Madridas", 2]]
Tada galime leisti vartotojui pasirinkti miestą iš duomenų bazės naudojant šią formą:
<%= form_with model: @person do |form| %>
<%= form.select :city_id, City.order(:name).map { |city| [city.name, city.id] } %>
<% end %>
PASTABA: Atvaizduojant lauką belongs_to
asociacijai, turite nurodyti užsienio rakto pavadinimą (city_id
pavyzdyje aukščiau), o ne paties asociacijos pavadinimą.
Tačiau „Rails“ teikia pagalbinius metodus, kurie generuoja pasirinkimus iš kolekcijos, nereikalaujant išreiškiamai ją iteruoti. Šie pagalbiniai metodai nustato kiekvieno objekto kolekcijoje vertę ir teksto žymėjimą, iškviesdami nurodytus metodus.
5.1 collection_select
pagalbinis metodas
Norėdami sugeneruoti pasirinkimo langelį, galime naudoti collection_select
:
<%= form.collection_select :city_id, City.order(:name), :id, :name %>
Išvestis:
<select name="person[city_id]" id="person_city_id">
<option value="3">Berlinas</option>
<option value="1">Čikaga</option>
<option value="2">Madridas</option>
</select>
PASTABA: Naudojant collection_select
, pirmiausia nurodome vertės metodą (:id
pavyzdyje aukščiau), o antra - teksto žymėjimo metodą (:name
pavyzdyje aukščiau). Tai priešinga tvarka nei nurodomi pasirinkimai naudojant select
pagalbinį metodą, kur teksto žymėjimas eina pirmas, o vertė - antras.
5.2 collection_radio_buttons
pagalbinis metodas
Norėdami sugeneruoti rinkinį radijo mygtukų, galime naudoti collection_radio_buttons
:
<%= form.collection_radio_buttons :city_id, City.order(:name), :id, :name %>
Išvestis:
<input type="radio" name="person[city_id]" value="3" id="person_city_id_3">
<label for="person_city_id_3">Berlinas</label>
<input type="radio" name="person[city_id]" value="1" id="person_city_id_1">
<label for="person_city_id_1">Čikaga</label>
<input type="radio" name="person[city_id]" value="2" id="person_city_id_2">
<label for="person_city_id_2">Madridas</label>
5.3 collection_check_boxes
pagalbinis metodas
Norėdami sugeneruoti žymėjimo langelius - pavyzdžiui, palaikyti has_and_belongs_to_many
asociaciją - galime naudoti collection_check_boxes
:
<%= form.collection_check_boxes :interest_ids, Interest.order(:name), :id, :name %>
Išvestis:
<input type="checkbox" name="person[interest_id][]" value="3" id="person_interest_id_3">
<label for="person_interest_id_3">Inžinerija</label>
<input type="checkbox" name="person[interest_id][]" value="4" id="person_interest_id_4">
<label for="person_interest_id_4">Matematika</label>
<input type="checkbox" name="person[interest_id][]" value="1" id="person_interest_id_1">
<label for="person_interest_id_1">Mokslas</label>
<input type="checkbox" name="person[interest_id][]" value="2" id="person_interest_id_2">
<label for="person_interest_id_2">Technologija</label>
6 Failų įkėlimas
Daugelis užduočių apima failo įkėlimą, ar tai būtų asmenio nuotrauka ar CSV failas, kuriame yra duomenų, skirtų apdoroti. Failo įkėlimo laukai gali būti atvaizduojami naudojant file_field
pagalbinį metodą.
<%= form_with model: @person do |form| %>
<%= form.file_field :picture %>
<% end %>
Svarbiausia atsiminti, kad sugeneruotos formos enctype
atributas turi būti nustatytas kaip "multipart/form-data". Tai automatiškai atliekama naudojant file_field
viduje form_with
. Taip pat galite nustatyti atributą rankiniu būdu:
<%= form_with url: "/uploads", multipart: true do |form| %>
<%= file_field_tag :picture %>
<% end %>
Atkreipkite dėmesį, kad, vadovaujantis form_with
konvencijomis, laukų pavadinimai šiuose dviejuose formose taip pat skirsis. Tai reiškia, kad pirmos formos lauko pavadinimas bus person[picture]
(pasiekiamas per params[:person][:picture]
), o antros formos lauko pavadinimas bus tiesiog picture
(pasiekiamas per params[:picture]
).
6.1 Kas yra įkelta
Objektas params
maiše yra ActionDispatch::Http::UploadedFile
pavyzdys. Šis fragmentas įrašo įkeltą failą #{Rails.root}/public/uploads
aplanko po to pačiu pavadinimu kaip ir originalus failas.
def upload
uploaded_file = params[:picture]
File.open(Rails.root.join('public', 'uploads', uploaded_file.original_filename), 'wb') do |file|
file.write(uploaded_file.read)
end
end
Kai failas yra įkeltas, yra daugybė potencialių užduočių, pradedant nuo to, kur saugoti failus (diske, „Amazon S3“ ir kt.), susiejant juos su modeliais, keičiant paveikslėlių failų dydį ir generuojant miniatiūras ir kt. Active Storage skirtas padėti šioms užduotims.
7 Formų kūrimo adaptavimas
form_with
ir fields_for
grąžinamas objektas yra ActionView::Helpers::FormBuilder
klasės objektas. Formų kūrėjai apibrėžia formos elementų atvaizdavimo logiką vienam objektui. Nors galite rašyti pagalbines funkcijas formoms kaip įprasta, taip pat galite sukurti ActionView::Helpers::FormBuilder
klasės paveldėjimą ir ten pridėti pagalbines funkcijas. Pavyzdžiui,
<%= form_with model: @person do |form| %>
<%= text_field_with_label form, :first_name %>
<% end %>
gali būti pakeistas į
<%= form_with model: @person, builder: LabellingFormBuilder do |form| %>
<%= form.text_field :first_name %>
<% end %>
apibrėžiant LabellingFormBuilder
klasę panašiai kaip ši:
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
def text_field(attribute, options = {})
label(attribute) + super
end
end
Jei dažnai naudojate šį kodą, galite apibrėžti labeled_form_with
pagalbinę funkciją, kuri automatiškai pritaikys builder: LabellingFormBuilder
parinktį:
def labeled_form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
options[:builder] = LabellingFormBuilder
form_with model: model, scope: scope, url: url, format: format, **options, &block
end
Formų kūrėjas taip pat nusprendžia, kas vyksta, kai rašote:
<%= render partial: f %>
Jei f
yra ActionView::Helpers::FormBuilder
klasės objektas, tai atvaizduos form
dalinį, nustatant dalinio objektą kaip formos kūrėją. Jei formos kūrėjas yra LabellingFormBuilder
klasės objektas, tai bus atvaizduojamas labelling_form
dalinis.
8 Parametrų pavadinimų konvencijų supratimas
Formų reikšmės gali būti tiesiogiai params
hash'o viršuje arba gali būti įdėtos į kitą hash'ą. Pavyzdžiui, standartinėje create
veiksmo funkcijoje, skirtai Person
modeliui, params[:person]
paprastai yra hash'as, kuriame yra visi žmogaus sukūrimui skirti atributai. params
hash'as taip pat gali turėti masyvus, masyvus iš hash'ų ir t.t.
Pagrindinėje HTML formos struktūroje nėra jokios struktūruotos informacijos, viskas, ką jos generuoja, yra pavadinimo-reikšmės poros, kur poros yra paprastos eilutės. Masyvai ir hash'ai, kuriuos matote savo programoje, yra rezultatas tam tikrų parametrų pavadinimų konvencijų, kurias naudoja Rails.
8.1 Pagrindinės struktūros
Dvi pagrindinės struktūros yra masyvai ir hash'ai. Hash'ai atitinka sintaksę, naudojamą prieigai prie params
hash'o reikšmių. Pavyzdžiui, jei forma yra:
<input id="person_name" name="person[name]" type="text" value="Henry"/>
params
hash'e bus
{ 'person' => { 'name' => 'Henry' } }
ir params[:person][:name]
gaus pateiktą reikšmę valdiklyje.
Hash'ai gali būti bet kokiu lygiu įdėti vienas į kitą, pavyzdžiui:
<input id="person_address_city" name="person[address][city]" type="text" value="New York"/>
sukurs params
hash'ą
{ 'person' => { 'address' => { 'city' => 'New York' } } }
Įprastai Rails ignoruoja pasikartojančius parametrų pavadinimus. Jei parametrų pavadinimas baigiasi tuščiu laužtinių skliaustų rinkiniu []
, jie bus kaupiami masyve. Jei norite, kad vartotojai galėtų įvesti kelis telefono numerius, galite į formą įdėti šį kodą:
<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>
Tai sukurs params[:person][:phone_number]
masyvą, kuriame bus įvesti telefono numeriai.
8.2 Jų derinimas
Galime derinti šiuos du konceptus. Vienas hash'o elementas gali būti masyvas, kaip ir ankstesniame pavyzdyje, arba galite turėti masyvą iš hash'ų. Pavyzdžiui, forma gali leisti jums sukurti bet kokį adresų skaičių, kartojant šį formos fragmentą
<input name="person[addresses][][line1]" type="text"/>
<input name="person[addresses][][line2]" type="text"/>
<input name="person[addresses][][city]" type="text"/>
<input name="person[addresses][][line1]" type="text"/>
<input name="person[addresses][][line2]" type="text"/>
<input name="person[addresses][][city]" type="text"/>
Tai sukurs params[:person][:addresses]
masyvą iš hash'ų su raktiniais žodžiais line1
, line2
ir city
.
Tačiau yra apribojimas: nors hash'us galima bet kokiu lygiu įdėti vieną į kitą, leidžiama tik viena "masyvų lygio" lygi. Masyvus paprastai galima pakeisti hash'ais; pavyzdžiui, vietoj modelio objektų masyvo galima turėti modelio objektų hash'ą, kurio raktai yra jų id, masyvo indeksas arba kitas parametras.
ĮSPĖJIMAS: Masyvo parametrai nesiderina su check_box
pagalbininku. Pagal HTML specifikaciją, nepažymėti žymimieji langeliai neišsiunčia jokios reikšmės. Tačiau dažnai patogu, kad žymimasis langelis visada išsiųstų reikšmę. check_box
pagalbininkas tai imituoja, sukurdamas pagalbinį paslėptą įvesties lauką su tuo pačiu pavadinimu. Jei žymimasis langelis nepažymėtas, siunčiamas tik paslėptas įvesties laukas, o jei pažymėtas, siunčiami abu, tačiau žymimojo langelio siunčiama reikšmė turi pirmenybę.
8.3 fields_for
pagalbininko :index
parinktis
Tarkime, norime atvaizduoti formą su kiekvieno asmens adreso laukų rinkiniu. fields_for
pagalbininkas su savo :index
parinktimi gali padėti:
<%= form_with model: @person do |person_form| %>
<%= person_form.text_field :name %>
<% @person.addresses.each do |address| %>
<%= person_form.fields_for address, index: address.id do |address_form| %>
<%= address_form.text_field :city %>
<% end %>
<% end %>
<% end %>
Priimant, kad asmuo turi dvi adresus su ID 23 ir 45, aukščiau pateikta forma panašiai atvaizduotų rezultatą:
<form accept-charset="UTF-8" action="/people/1" method="post">
<input name="_method" type="hidden" value="patch" />
<input id="person_name" name="person[name]" type="text" />
<input id="person_address_23_city" name="person[address][23][city]" type="text" />
<input id="person_address_45_city" name="person[address][45][city]" type="text" />
</form>
Tai sukels params
maišos objektą, kuris atrodo taip:
{
"person" => {
"name" => "Bob",
"address" => {
"23" => {
"city" => "Paris"
},
"45" => {
"city" => "London"
}
}
}
}
Visi formos įvesties laukai susiejami su "person"
maišos objektu, nes mes iškvietėme fields_for
su person_form
formos kūrėju. Taip pat, nurodydami index: address.id
, mes atvaizdavome kiekvieno miesto įvesties lauko name
atributą kaip person[address][#{address.id}][city]
, o ne person[address][city]
. Taip mes galime nustatyti, kurie Adreso įrašai turėtų būti modifikuoti apdorojant params
maišą.
Galite perduoti kitus svarbius skaičius ar eilutes per :index
parinktį. Netgi galite perduoti nil
, kuris sukurs masyvo parametrą.
Norėdami sukurti sudėtingesnius įdėjimus, galite aiškiai nurodyti įvesties lauko pavadinimo pradžią. Pavyzdžiui:
<%= fields_for 'person[address][primary]', address, index: address.id do |address_form| %>
<%= address_form.text_field :city %>
<% end %>
sukurs įvesties laukus kaip:
<input id="person_address_primary_23_city" name="person[address][primary][23][city]" type="text" value="Paris" />
Taip pat galite perduoti :index
parinktį tiesiogiai pagalbininkams, tokiems kaip text_field
, bet paprastai mažiau kartojama nurodyti tai formos kūrėjo lygyje nei atskiruose įvesties laukuose.
Bendrai kalbant, galutinis įvesties lauko pavadinimas bus fields_for
/ form_with
suteikto pavadinimo, :index
parinkties reikšmės ir atributo pavadinimo sujungimas.
Galų gale, kaip sutrumpinimą, vietoj :index
nurodymo ID (pvz., index: address.id
), galite pridėti "[]"
prie pateikto pavadinimo. Pavyzdžiui:
<%= fields_for 'person[address][primary][]', address do |address_form| %>
<%= address_form.text_field :city %>
<% end %>
sukuria visiškai tą patį rezultatą kaip ir mūsų pradinis pavyzdys.
9 Formos į išorinius išteklius
Rails formos pagalbininkai taip pat gali būti naudojami formos kūrimui, skirtam duomenims siųsti į išorinį išteklių. Tačiau kartais gali būti būtina nustatyti authenticity_token
ištekliui; tai galima padaryti perduodant authenticity_token: 'your_external_token'
parametrą form_with
parinktims:
<%= form_with url: 'http://farfar.away/form', authenticity_token: 'external_token' do %>
Formos turinys
<% end %>
Kartais siunčiant duomenis į išorinį išteklių, pvz., mokėjimo šliuzą, formoje galima naudoti tik tam tikrus laukus, kurie yra apriboti išorinio API. Tokiu atveju gali būti nepageidautina generuoti authenticity_token
. Norėdami nesiųsti žetono, tiesiog perduokite false
:authenticity_token
parinkčiai:
<%= form_with url: 'http://farfar.away/form', authenticity_token: false do %>
Formos turinys
<% end %>
10 Kompleksinių formų kūrimas
Daugelis programų išauga iš paprastų formų, kurios redaguoja vieną objektą. Pavyzdžiui, kuriant Person
(asmenį), galite norėti leisti vartotojui (tame pačiame forme) sukurti kelis adresų įrašus (namas, darbas ir kt.). Vėliau redaguojant tą asmenį, vartotojas turėtų galėti pridėti, pašalinti arba pakeisti adresus pagal poreikį.
10.1 Modelio konfigūravimas
Active Record teikia modelio lygio palaikymą naudojant accepts_nested_attributes_for
metodą:
class Person < ApplicationRecord
has_many :addresses, inverse_of: :person
accepts_nested_attributes_for :addresses
end
class Address < ApplicationRecord
belongs_to :person
end
Tai sukuria addresses_attributes=
metodą Person
modelyje, kuris leidžia jums kurti, atnaujinti ir (neprivalomai) naikinti adresus.
10.2 Įdėti formą
Ši forma leidžia vartotojui sukurti Person
ir susijusius adresus.
<%= form_with model: @person do |form| %>
Adresai:
<ul>
<%= form.fields_for :addresses do |addresses_form| %>
<li>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind %>
<%= addresses_form.label :street %>
<%= addresses_form.text_field :street %>
...
</li>
<% end %>
</ul>
<% end %>
Kai asociacija priima įdėtas atributus, fields_for
atvaizduoja savo bloką kiekvienam asociacijos elementui. Ypač, jei asmuo neturi adresų, nieko neatvaizduoja. Dažnas modelio kūrėjo modelis yra sukurti vieną ar daugiau tuščių vaikų, kad vartotojui būtų rodomas bent vienas laukų rinkinys. Pavyzdys žemiau rezultatuose rodo 2 adresų laukų rinkinius naujo asmens formoje.
def new
@person = Person.new
2.times { @person.addresses.build }
end
fields_for
grąžina formos kūrėją. Parametrų pavadinimas bus tai, ko accepts_nested_attributes_for
tikisi. Pavyzdžiui, kuriant vartotoją su 2 adresais, pateikti parametrai atrodytų taip:
{
'person' => {
'name' => 'John Doe',
'addresses_attributes' => {
'0' => {
'kind' => 'Home',
'street' => '221b Baker Street'
},
'1' => {
'kind' => 'Office',
'street' => '31 Spooner Street'
}
}
}
}
Raktažodžių reikšmės :addresses_attributes
raktų yra nesvarbios; tačiau jos turi būti sveikųjų skaičių eilutės ir skirtingos kiekvienam adresui.
Jei susijęs objektas jau yra išsaugotas, fields_for
automatiškai sugeneruoja paslėptą įvestį su išsaugoto įrašo id
. Tai galima išjungti, perduodant include_id: false
į fields_for
.
10.3 Valdiklis
Kaip įprasta, jums reikia paskelbti leidžiamus parametrus valdiklyje, prieš juos perduodant modeliui:
def create
@person = Person.new(person_params)
# ...
end
private
def person_params
params.require(:person).permit(:name, addresses_attributes: [:id, :kind, :street])
end
10.4 Objektų šalinimas
Galite leisti vartotojams ištrinti susijusius objektus, perduodami allow_destroy: true
į accepts_nested_attributes_for
class Person < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses, allow_destroy: true
end
Jei objekto atributų maišas turi raktą _destroy
su reikšme, kuri vertinama kaip true
(pvz., 1, '1', true arba 'true'), tada objektas bus sunaikintas.
Ši forma leidžia vartotojams pašalinti adresus:
<%= form_with model: @person do |form| %>
Adresai:
<ul>
<%= form.fields_for :addresses do |addresses_form| %>
<li>
<%= addresses_form.check_box :_destroy %>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind %>
...
</li>
<% end %>
</ul>
<% end %>
Nepamirškite atnaujinti leidžiamų parametrų valdiklyje, kad būtų įtrauktas
laukas _destroy
:
def person_params
params.require(:person).
permit(:name, addresses_attributes: [:id, :kind, :street, :_destroy])
end
10.5 Tuščių įrašų prevencija
Daugeliu atvejų naudinga ignoruoti laukų rinkinius, kuriuos vartotojas neįvedė. Tai galima valdyti, perduodant :reject_if
funkciją į accepts_nested_attributes_for
. Ši funkcija bus iškviesta su kiekvienu atributų maišu, pateiktu formos. Jei funkcija grąžina true
, tada Active Record nekuria susijusio objekto tam maišui. Pavyzdys žemiau bandys sukurti adresą tik tada, kai nustatytas kind
atributas.
ruby
class Person < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses, reject_if: lambda { |attributes| attributes['kind'].blank? }
end
Norint patogumo vietoj to galite perduoti simbolį :all_blank
, kuris sukurs proc, kuris atmetys įrašus, kuriuose visi atributai yra tušti, išskyrus bet kokį _destroy
reikšmę.
10.6 Laukų pridėjimas dinamiškai
Vietoje to, kad iš anksto atvaizduotumėte kelis laukų rinkinius, galite norėti pridėti juos tik tada, kai vartotojas paspaudžia mygtuką "Pridėti naują adresą". "Rails" šiam tikslui nepateikia jokios įdiegto palaikymo. Generuodami naujus laukų rinkinius, turite užtikrinti, kad susijusio masyvo raktas būtų unikalus - dabartinė JavaScript datos reikšmė (milisekundės nuo epochos) yra paplitęs pasirinkimas.
11 Naudodami žymos pagalbininkus be formos kūrėjo
Jei norite atvaizduoti formos laukus ne formos kūrėjo kontekste, "Rails" teikia žymos pagalbininkus bendriems formos elementams. Pavyzdžiui, check_box_tag
:
<%= check_box_tag "accept" %>
Išvestis:
<input type="checkbox" name="accept" id="accept" value="1" />
Bendrai, šie pagalbininkai turi tą patį pavadinimą kaip ir jų formos kūrėjo atitikmenys, tik su _tag
priesaga. Visą sąrašą rasite FormTagHelper
API dokumentacijoje.
12 Naudodami form_tag
ir form_for
Prieš pristatant form_with
"Rails" 5.1 versijoje, jo funkcionalumas buvo padalintas tarp form_tag
ir form_for
. Abi funkcijos dabar yra švelniai pasenusios. Dokumentacija apie jų naudojimą gali būti rasta šio vadovo senesnėse versijose.
Atsiliepimai
Jūs esate skatinami padėti pagerinti šio vadovo kokybę.
Prašome prisidėti, jei pastebite rašybos klaidų ar faktinių klaidų. Norėdami pradėti, galite perskaityti mūsų dokumentacijos prisidėjimo skyrių.
Taip pat gali būti nepilnos informacijos arba informacijos, kuri nėra atnaujinta. Prašome pridėti bet kokią trūkstamą dokumentaciją pagrindiniam. Patikrinkite Edge vadovus pirmiausia, ar problemas jau išspręsta arba ne pagrindinėje šakoje. Patikrinkite Ruby on Rails vadovų gaires dėl stiliaus ir konvencijų.
Jei dėl kokios nors priežasties pastebite kažką, ką reikia ištaisyti, bet negalite patys tai pataisyti, prašome pranešti apie problemą.
Ir galiausiai, bet ne mažiau svarbu, bet koks diskusijos dėl Ruby on Rails dokumentacijos yra labai laukiamos oficialiame Ruby on Rails forume.