Jestem poczatkujacym ROR’owcem. Pisze pewna testowa mala aplikacje gdzie uzywam relacji many to many. Zrobiłem wszystko wg. pewnego tutorialu. W skrocie mam
1.tabelke adds
2.tabelke skills
3.tabelke adds_skills ( gdzie mam tylko add_id, i skill_id )
w modelu add mam has_and_belongs_to_many :skills
a w modelu skill mam has_and_belongs_to_many :adds
Kiedy dodaje sobie jakis add, listuje skille do wyboru jako checkbox w ten sposob
<% for skill in @skills %>
"
name="skill_ids[ ]"
value="<%= skill.id %>">
<%= skill.name%>
<%end%>
i wszystko ładnie wyglada, zaznaczam sobie skille, dodaja sie wszystkie pozostale informacje do tabeli adds, natomiast niestety w tabeli adds_skills nic sie nie dodaje.
Nie mam zadnego bledu, w development log mam tylko sql’owy insert pozostalych rzeczy, natomiast brak insertu w tabele adds_skills, mimo ze zaznaczylem oczywiscie kilka skillow. Nie wiem gdzie szukac bledu.
def update
@add = Add.find(params[:id])
begin
# sprawa jest powazna wiec transakcja
Add.transaction do
@add.skill_ids = (params[:skills] or []).collect { |s| s.to_i }
@add.update_attributes(params[:add])
end
# udalo sie: flash[:notice] i redirect_to ...
rescue => e
# dobrze wiedziec co sie stalo, wiec np.
@add.errors.add_to_base(CGI::escapeHTML(e.message))
render(:action => 'edit')
end
end
Ogolnie proponuje tego typu rozwiazanie (fragm. kontrolera, ale tego typu logike poprawniej byloby przeniesc do modelu jako swoistego DAO i wystawic odpowiednie metody kontrolerowi)
def create
@add = Add.new(params[:add])
create_update_common
if @successful
# powidlo sie: flash[:notice] i redirect_to ... lub ajax voodoo
else
render(:action => 'new')
end
end
def update
@add = Add.find(params[:id])
@add.attributes = params[:add] #nie zapisuje jeszcze w bazie
create_update_common
if @successful
# powidlo sie: flash[:notice] i redirect_to ... lub ajax voodoo
else
render(:action => 'edit')
end
end
def create_update_common
Add.transaction do
@add.save! # ta wyrzuca wyjatek, zwykle save zwraca false/true i nie bedzie rollbacku!
@add.skill_ids = (params[:skills] or []).collect { |s| s.to_i }
# latwo sprawdzic wyjatek i rollback,
# np: jakiekolwiek nie istniejace jescze w tabeli skills
# @add.skill_ids = [1231231,123111]
# wyrzuci ActiveRecord::RecordNotFound i wiadomosc w sylu:
# Couldn't find all Skills with IDs (1231231,123111)
end
rescue ActiveRecord::RecordInvalid # nie validuje
@successful = false
rescue => e # wszystkie inne wyjatki
@succesful = false
@add.errors.add_to_base(CGI::escapeHTML(e.message))
end
Oczywiscie zakladam, ze RDBMS wspiera transakcje (InnoDB, nie MyISAM).
Dziękuje za odpowiedzi!
Dzięki wam udało mi się to uruchomić wkońcu.
Musiałem zmienić jeszcze jedną rzecz w view w atrybutach checkboxa.
name=“skill_ids[ ]” na name=“add[skill_ids][]”
i wszystko działa.
Mam jeszcze jedno pytanie…ten maly cms ktory robie mialby obslugiwac rozne jezyki, czyli rozne labele dla formularzy, rozne bledy itd. Pisalem na ruby-forum i doradzali mi plugin globalize lub inne lokalizacyjne pluginy. Druga alternatywa bylo dodanie tego do bazy, i nie wiem ktora droga lepsza.