Dodawanie kilku rekordów

Cześć,

Mam podstronę Dodaj Ksiązkę, gdzie dodaje się ksiązkę. Wybiera się Autora i wpisuje się Tytuł książki. Chciałbym dodać na tej podstronie przycisk dodaj kolejną książkę. Po kliknięciu pokazywałoby się kolejne pola, skopiowane pole autora i czyste pole tytuł książki.

Chciałbym tak dodawać “nieskończoną” liczbę pozycji. Dodanie wszystkich książek następowałoby dopiero po naciśnięciu innego przycisku.

Jak się zabrać za to?

Nie jest tu może pokazane najlepsze rozwiązanie na świecie, ale Ryan jakiś czas temu zrobił na ten temat railscastodświeżony railscast jest lepszy :wink:

Dzięki, jakoś sobie z tym poradzę.

Jeszcze pytanko,
Category ma pole id oraz name.
Article ma pole category_id itd
mam model Category (has_many :articles) i Article belongs_to :category i chciałbym w formie article podczas tworzenia mieć pole nazwa kategorii gdzie wpisywałoby się nazwe kategorii która leciałaby do tabeli Category a w article zostawałby id. Jak to ruszyć? Próbowałem tak jak tu ale ni ch http://railscasts.com/episodes/57-create-model-through-text-field

[quote=chinchin]Dzięki, jakoś sobie z tym poradzę.

Jeszcze pytanko,
Category ma pole id oraz name.
Article ma pole category_id itd
mam model Category (has_many :articles) i Article belongs_to :category i chciałbym w formie article podczas tworzenia mieć pole nazwa kategorii gdzie wpisywałoby się nazwe kategorii która leciałaby do tabeli Category a w article zostawałby id. Jak to ruszyć? Próbowałem tak jak tu ale ni ch http://railscasts.com/episodes/57-create-model-through-text-field[/quote]
co konkretnie nie działa z tego railscastu? masz jakiś błąd czy nie tworzy kategorii?

Jeśli chciałbym zrobić jedno pole tekstowe ksiązki, w którym możemy wpisać X książek (nalepiej duża textarea rozsuwana), każda nowa książka w następnej linii, a następnie dodać to do bazy jako osobne rekordy? 1 książka = 1 rekord w bazie.

Jak to ruszyć?

może to zadziała

each_line

tu przykład podobny tylko zczytuje z pliku

Ps nie sprawdzałem tego.

Zrobiłem tak:

mikolajs_controller:

[code] def new

respond_to do |format|
  format.html # new.html.erb
  format.json { render json: @mikolaj }
end

end

GET /mikolajs/1/edit

def edit
@mikolaj = Mikolaj.find(params[:id])
end

POST /mikolajs

POST /mikolajs.json

def create
@licznik=0
params[:s].each_line do |mikolaj|
if mikolaj == nil
else
@mikolaj = Mikolaj.new(:name => mikolaj)
@mikolaj.save
@licznik +=1
end
end
respond_to do |format|
format.html { redirect_to mikolajs_path, notice: “Dodano #{@licznik} mikolajow” }
format.json { render json: mikolajs_path, status: :created, location: mikolajs_path }
end
end[/code]
new.html.erb

[code]

New mikolaj

<%= form_tag(:controller => "mikolajs", :action => "create", :method => "post") do %> <%= label_tag(:s, "Dodaj Mikołajów") %>
<%= text_area_tag(:s,nil, :rows => 20, :cols => 40) %>
<%= submit_tag("Dodaj Mikołajów") %>
<% end %>

<%= link_to ‘Back’, mikolajs_path %>[/code]
mkolaj.rb

class Mikolaj < ActiveRecord::Base attr_accessible :name validates_presence_of :name end
Można to łatwiej zrobić? To działa, ale pytanie czy wszystko jest ok.

Na nazwy nie patrzcie, bo bawiłem się tym w osobnej aplikacji

[code=ruby]def create
begin
n = Mikolaj.create_from_text(params[:s])

respond_to |format|
 format.html { redirect_to mikolajs_path, notice: "Dodano #{n} mikolajow" }
 format.json { render json: mikolajs_path, status: :created, location: mikolajs_path }
end

rescue ActiveRecord::RecordInvalid
render :new
end
end

class Mikolaj < AR::Base
def self.create_from_text(txt)
txt = txt.split("\n").compact

txt.each do |mikolaj|
  create!(name: mikolaj)
end

txt.length

end
end[/code]
ewentualnie tak jeżeli nie chcesz używać wyjątków:

[code=ruby]def create
if n = Mikolaj.create_from_text(param[:s])
respond_to |format|
format.html { redirect_to mikolajs_path, notice: “Dodano #{n} mikolajow” }
format.json { render json: mikolajs_path, status: :created, location: mikolajs_path }
end
else
render :new
end
end

class Mikolaj < AR::Base
def self.create_from_text(txt)
txt = txt.split("\n").compact

txt.map do |o|
  mikolaj = new(name: o)
  mikolaj.save
end

txt.all? ? txt.length : nil

end
end[/code]

dobry kierunek, ale compacta (łapie tylko nile, których po splicie na stringu nie będzie) trzebaby zastąpić reject(&:empty?), a w drugim przykładzie dodać ! do mapa.
Przy obecnej walidacji będzie to działać, ale aż prosi się o dodanie transakcyjności.

[code=ruby]def create
if n = Mikolaj.create_from_text(param[:s])
respond_to |format|
format.html { redirect_to mikolajs_path, notice: “Dodano #{n} mikolajow” }
format.json { render json: mikolajs_path, status: :created, location: mikolajs_path }
end
else
render :new
end
end

class Mikolaj < AR::Base
def self.create_from_text(txt)
txt = txt.split("\n").reject(&:empty?)

txt.map! do |o|
  mikolaj = new(name: o)
  mikolaj.save
end

txt.all? ? txt.length : nil

end
end[/code]

Transakcyjności ?

http://api.rubyonrails.org/classes/ActiveRecord/Transactions

Po prostu żeby to zrobić w jednym połączeniu z baza danych czy co?

Zresztą odpuszczę, za wysoka szkoła jazdy

To bardzo ważne, więc bym nie odpuszczał. Poczytaj i zwiększ swoją wiedze, albo nie rób wcale.

materiałów jest masa:
http://www.tutorialspoint.com/sql/sql-transactions.htm

pocztaj i zrozum

Chodziło mi o ror.

Tak?

[code=ruby]class Mikolaj < AR::Base
def self.create_from_text(txt)
txt = txt.split("\n").reject(&:empty?)

transaction do
    txt.map! do |o|
    mikolaj = new(name: o)
    mikolaj.save
    end
  raise ActiveRecord::Rollback, "Nie dodano!!"
end

txt.all? ? txt.length : nil

end
end[/code]

Twoja odpowiedź świadczy o tym, że jednak nie zrozumiales, poczytaj jednak i tak chodzi ci o ror, ale pod spodem co masz?

OKej, nie wiem czy dobrze, ale zrobiłem tak i działa. Jak komuś się chce to niech zerknie na ta transakcyjność (btw jak sprawdzić czy wszystko leci za 1 połączeniem?)

[code=ruby]class Mikolaj < ActiveRecord::Base
attr_accessible :name

def self.create_from_text(txt)
txt = txt.split("\n").reject(&:blank?)

self.transaction do
txt.map! do |o|
  mikolaj = new(name: o)
  mikolaj.save
end
end
txt.all? ? txt.length : nil

end
end[/code]
Jeszcze kilka uwag, :emtpy nie działa, bo jak damy enter to to przyjmie, trzeba użyć blank?.

Druga sprawa, format nie działa, za mało argumentów. Wprawdzie zrobiłem to ze zwykłym redirectem, ale jak zwrócić coś do format?

respond_to |format|
 format.html { redirect_to mikolajs_path, notice: "Dodano #{n} mikolajow" }
 format.json { render json: mikolajs_path, status: :created, location: mikolajs_path }

[code=ruby]respond_to do |format|
end

a nie

respond_to |format|
end[/code]

[quote=chinchin]OKej, nie wiem czy dobrze, ale zrobiłem tak i działa. Jak komuś się chce to niech zerknie na ta transakcyjność (btw jak sprawdzić czy wszystko leci za 1 połączeniem?)

Jeszcze kilka uwag, :emtpy nie działa, bo jak damy enter to to przyjmie, trzeba użyć blank?.[/quote]
Blank faktycznie lepszy (łapie wszystkie białe znaki), empty? u mnie działa, bo mam enter = \n, ale z internetu (tak jak u Ciebie) może przyjść też \r\n (win).

Jeśli chodzi o kod w transakcji, to w takiej formie nie robi różnicy, nigdy nie poleci rollback.
Jest w activerecordzie jeden wyjątek (ActiveRecord::Rollback - http://apidock.com/rails/ActiveRecord/Transactions/ClassMethods ), który jest z automatu obsługiwany przez blok transakcji (tj. wyjątek zostaje złapany i następuje rollback, rollback nastąpiłby też dla innych wyjątków, ale je trzeba by osobno obsłużyć).
Dodałbym rzucanie tego wyjątku, jeśli któregoś tekstu nie uda się zapisać.
Dzięki temu masz jasną sytuację- albo wszystko, co wprowadził user zostało zapisane, albo nic.

[code]class Mikolaj < ActiveRecord::Base
attr_accessible :name

def self.create_from_text(txt)
txt = txt.split("\n").reject(&:blank?)

self.transaction do
  txt.map! do |o|
    mikolaj = new(name: o)
    mikolaj.save.tap { |saved| saved || raise ActiveRecord::Rollback }
    # tap to wygodna metoda, która przekazuje receiver do bloku i receiver zwraca
    # żeby do txt trafiał wynik zapisywania (true/false)
 end
end
txt.all? ? txt.length : nil

end
end[/code]

[code]mikolaj.save.tap { |saved| saved || raise ActiveRecord::Rollback }

tap to wygodna metoda, która przekazuje receiver do bloku i receiver zwraca

żeby do txt trafiał wynik zapisywania (true/false)[/code]

o ile się nie mylę, wystarczy użyć #save!, które zwróci true lub rzuci wyjątek

[quote=zlw][code]mikolaj.save.tap { |saved| saved || raise ActiveRecord::Rollback }

tap to wygodna metoda, która przekazuje receiver do bloku i receiver zwraca

żeby do txt trafiał wynik zapisywania (true/false)[/code]

o ile się nie mylę, wystarczy użyć #save!, które zwróci true lub rzuci wyjątek[/quote]
rzuci ActiveRecord::RecordInvalid, trzeba go złapać i obsłużyć, z ActiveRecord::Rollback masz to załatwione