Problem z duplikacja obiektu

Witam, chcę w swojej aplikcaji wykorzystać możliwość dodawania obiektów podobnych, coś w rodzaju opcji “Add Similar”.

Po wybraniu obiektu w aplikacji mam link w stylu “Dodaj podobny”:

<%= link_to "Dodaj Podobny", similar_video_url %>

routes.rb:

resources :videos do member do get :similar post :create_similar end end
Do duplikacji danych używam metody dup
. Po kliknięciu w link “Dodaj Podobny” jestem przekierowany do widoku w którym chciałbym poprawić tytuł, sezon, numer odcinka, link ale reszte rekordow chciałbym pozostawić takich samych jak dla kopiowanego modelu, jak np zdjęcie, kategorie itd…

Metody w kontrolerze:

[code]def similar
@video = Video.find(params[:id])
@similar = @video.dup
@similar.comments.destroy_all #usuwam komentarze jeśli są w kopiowanym obiekcie

respond_to do |format|
  format.html #similar.html.erb
  format.xml { render :xml => @similar }
end

end

def create_similar
@similar.user_id = current_user
Video.set_hits_counter(@similar.id)
respond_to do |format|
if @similar.save
format.html { redirect_to(@similar, :notice => ‘Video was successfully created.’) }
format.xml { render :xml => @video, :status => :created, :location => @similar }
else
format.html { render :action => “new” }
format.xml { render :xml => @similar.errors, :status => :unprocessable_entity }
end
end
end[/code]
Widok:

[code]<%= form_for @similar, :url => { :action => “create_similar” } do |f| %>
<% if @similar.errors.any? %>


<%= pluralize(@video.errors.count, “error”) %> prohibited this video from being saved:

  <ul>
  <% @video.errors.full_messages.each do |msg| %>
    <li><%= msg %></li>
  <% end %>
  </ul>
</div>

<% end %>

<%= f.label :tytuł %>
<%= f.text_field :title, :size => '61' %>
<%= f.label :odcinek %>
<%= f.number_field :episode %>
<%= f.label :sezon %>
<%= f.collection_select :season_id, Season.all, :id, :number, :prompt => 'Wybierz sezon...' %>
<%= f.label :link_do_serialu %>
<%= f.text_field :link, :size => '61' %>
<%= f.label :lista_tagów %> <%= f.text_field :tag_list %>
<% if current_user.try(:admin?) %>
<%= f.label :chcesz_opublikować_serial_na_stronie? %> <%= f.check_box :published %>
<%= f.label :chcesz_opublikować_serial_na_stronie_głównej? %> <%= f.check_box :mainpage %>
<% end %>
<%= f.submit %>
<% end %>[/code] Non stop przy tym podejściu w chwili gdy chcę zapisać taki obiekt dostaję komunikat:
undefined method `user_id=' for nil:NilClass

Obiekt @similar nie jest przekazywany do metody “create_similar”. Nie wiem jak to rozwiązać tak aby było to zgodne z Rails 3 i działało poprawnie. Czasami przy kliknięciu w przycisk “Dodaj Podobny” aplikacja mi się wiesza lub przycisk Zapisz nie reaguje.

Między tymi dwoma metodami masz request, więc zmienna @similar z metody similar już nie istnieje po przeładowaniu strony dla metody create_similar.

Może w formularzu trzymaj jeszcze w ukrytym polu ID kopiowanego obiektu i dopiero w metodzie create_similar go znajdź i zduplikuj tak jak to robisz wcześniej. No i w metodzie create_similar przydałoby się jeszcze uaktualnić pola które zmieniasz w formularzu w duplikowanym obiekcie i dopiero wtedy zapisać.

Hej,

pozmieniałem troszkę metody a mainowicie pozamieniałem nazwy zmiennych z simialar na video w metodach:

[code]def similar
@similar = Video.find(params[:id])
@video = @similar.dup
@video.comments.destroy_all

respond_to do |format|
  format.html #video.html.erb
  format.xml { render :xml => @video }
end

end

def create_similar
@similar = Video.find(params[:video][:video_id])
@video = @similar.dup
if @video.update_attribute(params[:video])
@video.user_id = current_user
Video.set_hits_counter(@video.id)
respond_to do |format|
if @video.save
format.html { redirect_to(@video, :notice => ‘Video was successfully created.’) }
format.xml { render :xml => @video, :status => :created, :location => @video }
else
format.html { render :action => “create_similar” }
format.xml { render :xml => @video.errors, :status => :unprocessable_entity }
end
end
else
respond_to do |format|
if @video.save
format.html { redirect_to(@video, :notice => ‘Video was successfully created.’) }
format.xml { render :xml => @video, :status => :created, :location => @video }
else
format.html { render :action => “create_similar” }
format.xml { render :xml => @video.errors, :status => :unprocessable_entity }
end
end
end
end[/code]
_simialr_form.html.erb:

<%= form_for(@video, :url => create_similar_video_path(@video)) do |f| %> <%= f.hidden_field :video_id, { :value => @video.id } %>
Niestety cały czas w źródle strony w ukrytym atrybucie mam id obiektou który chcę skopiować a nie nowe id obiektu skopiowanego i daltego przy zapisie do bazy pojawia sie błąd u dupliakcji danych w kolumnie id.

Metoda dup kopiuje wszystkie (w dużym uproszczeniu) pola danego obiektu, więc również i id. AR nie pozwoli Ci na zapis nowego obiektu z takim samym ID (i dobrze), więc najprostszym rozwiązaniem będzie jak napiszesz swoją własną metodę dup dla klasy Video, która będzie kopiować pola, na których Ci zależy.

Metoda clone robi to co trzeba (popatrz na definicję Object#clone oraz AR::Base#initialize_copy).

Pamiętajcie że od Rails 3.1 zmienia się semantyka clone i dup. U mnie kod w aplikacji wygląda w stylu:

class Controller def clone @video = Video.find(params[:id]).clone render :new end end

Hej, caly czas nie moge wpasc na pomysl jak stworzyc nowe id dla klonowanego obiektu. Czemu metoda new w metodzie create_similar nie tworzy nowego id dla takiego obiektu w tym przypadku?

[code]def similar
@video = Video.find(params[:id]).clone
@video.comments.destroy_all
render :similar
end

def create_similar
@video = Video.new(params[:video])
@video.user_id = current_user
Video.set_hits_counter(@video.id)
respond_to do |format|
if @video.save
format.html { redirect_to(@video, :notice => ‘Video was successfully created.’) }
format.xml { render :xml => @video, :status => :created, :location => @video }
else
format.html { render :action => “create_similar” }
format.xml { render :xml => @video.errors, :status => :unprocessable_entity }
end
end
end[/code]

Bo masz autoincrement na bazie i id jest dopiero pozyskiwane podczas save?

[quote=wlodi]@video = Video.find(params[:id]).clone @video.comments.destroy_all
[/quote]
Nie wydaje mi się, żeby 2 linijka była potrzebna.

Hej tutaj mam taki problem teraz:

Id zamiast wartoscia liczbową ma postać: “id”=>"-Bestia-The-Beast-S01S02"

Nie wiem dlaczego wartość ta jest taka. W modelu Video nadpisuje metodę to_param:

def to_param "#{id}-#{title.gsub(/[^a-z0-9]+/i, '-')}" end
Metody w kontrolerze zmieniłem na:

[code] def similar
@video = Video.find(params[:id].to_param).clone
render :similar
end

def create_similar
@video = Video.new(params[:video])
respond_to do |format|
if @video.save
@video.user_id = current_user
Video.set_hits_counter(@video.id)
render :show
else
render :similar
end
end
end[/code]
Routing mam taki:

resources :videos do resources :comments resources :seasons collection do get :tag end member do get :similar post :create_similar post :notify_friend post :copyright_violation end end
Parametry:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"x5W0VNwHiXx9Ry/L46VR98lCrJ1Ewu/zouQZMOSc5Q4=", "video"=>{"title"=>"Bestia (The Beast) S01S02", "episode"=>"4", "season_id"=>"18", "link"=>"http://www.megavideo.com/?v=8GXPxzxzZCTCxzxz3232", "tag_list"=>"S01E06, Bestia, The Beast", "published"=>"1", "mainpage"=>"1"}, "commit"=>"Create Video", "id"=>"-Bestia-The-Beast-S01S02"}

Pomimo tego że mam render ustawiony na akcję :show wywołuje mi się widok odpowiadający nazwie akcji czyli create_similar.html.erb. ?Jak to zmienić?

[quote=wlodi]def to_param "#{id}-#{title.gsub(/[^a-z0-9]+/i, '-')}" end
[/quote]
Sorki ze robie offtopa, ale juz chyba 3 raz widze ze tutaj w to_param ktos uzywa gsub. Ja uzywam parameterize i zaczynam sie zastanawiac czy z ta metoda jest zwiazane jakies ‘gotcha’ o ktorym nie wiem.