Wyszukiwanie po emailu

#asocjacje advertiser has_many ad #ad_controller.rb def create @ad = Ad.new(params[:ad]) @adv = Advertiser.find_by_email(params[:ad][:email]) if @ad.save if @adv @ad.update_attributes(:advertiser_id => @adv.id) redirect_to root_path flash[:notice] = "Ogłoszenie przekazane do weryfikacji!" else AdMailer.ad_token(@ad).deliver redirect_to root_path flash[:notice] = "Ogłoszenie przekazane do potwierdzenia emaila!" end else render :new end end
Czy można część tej logiki przesunąć do modelu?

Napisz sobie wirtualny atrybut email= w modelu Ad może ?

Drugi mój pomysł.

[code=ruby] # kontroller
def create
@ad = Ad.new(params[:ad])
if result = @ad.create_by(params[:ad][:email])
flash[:notice] = result # http://blog.robert.pankowecki.pl/2011/12/communication-between-controllers-and.html
redirect_to root_path
else
flash[:alert] = :invalid
render :new
end
end

model

def create_by(email)
self.advertiser = Advertiser.find_by_email(email)
return false unless save
return if self.advertiser ?
:awaiting_verification
else
AdMailer.ad_token(self).deliver
:awaiting_email_confirmation
end
end[/code]

[quote=paneq]Drugi mój pomysł.

[code=ruby] # kontroller
def create
@ad = Ad.new(params[:ad])
if result = @ad.create_by(params[:ad][:email])
flash[:notice] = result # http://blog.robert.pankowecki.pl/2011/12/communication-between-controllers-and.html
redirect_to root_path
else
flash[:alert] = :invalid
render :new
end
end

model

def create_by(email)
self.advertiser = Advertiser.find_by_email(email)
return false unless save
return if self.advertiser ?
:awaiting_verification
else
AdMailer.ad_token(self).deliver
:awaiting_email_confirmation
end
end
end[/code]
[/quote]
To ja bym chyba całość (razem z #new) przeniósł do modelu.

[code=ruby]def create
if msg = Ad.create_and_verify(params[:ad])
flash.notice = t(“ad.create.#{msg}”)
redirect_to root_path
else
flash.now.alert = ‘invalid’
render :new
end
end

def create_and_verify(params)
advertiser = Advertiser.find_by_email(params[:email])
ad = new(params, advertiser: advertiser)

return false unless ad.save

if advertiser
:awaiting_verification
else
AdMailer.ad_token(ad).deliver
:awaiting_email_confirmation
end
end[/code]

Chciałeś zrobić chyba self.create_and_verify tak? Ja się celowo wystrzegałem tworzenia nowej metody klasy. Osobiście sam rozwiązałbym to jeszcze zupełnie inaczej ale to już byłby głębszy refactoring. To co napisałem wydawało mi się najprostsze do osiągnięcia w stosunku do zastanego kodu.

I takie rzeczy jak “weryfikacja” mówią mi, że może jest tu jakaś maszyna stanów i warto by zaprząc gema do tego.

if advertiser :awaiting_verification else AdMailer.ad_token(ad).deliver :awaiting_email_confirmation end
wytłumaczylibyście mi tą część?, chodzi o :awaiting_verification i :awaiting_email_confirmation
Dzięki za pomoc, właśnie szukam jakichś artykułów o przesuwaniu logiki do modelu.

Dostaję jeszcze taki błąd

ad.rb:39: syntax error, unexpected keyword_else, expecting ':' (SyntaxError)

Ale co tu tłumaczyć? Zwykłe symbole.

Okej, nie używałem jeszcze nigdy locales :slight_smile:
Głupie pytanie :slight_smile:

[quote=regedarek]Dostaję jeszcze taki błąd

ad.rb:39: syntax error, unexpected keyword_else, expecting ':' (SyntaxError)

[/quote]
Ale czyjego kodu użyłeś?

@paneq w Twoim kodzie był chyba błąd przy if-ie - niepotrzebny “?”. Ano i oczywiście chodziło o self.create_and_verify :wink:

Tak dzięki to akurat zauważyłem :stuck_out_tongue:

Tak błąd przy kodzie @paneq

Jeszcze raz dzięki za pomoc teraz muszę wszystkie kontrolery przerobić :slight_smile:

Przy okazji cały czas się wkurzam na czas testowania. I niepodobają mi się moje testy. Może zerkniecie okiem.
Myślę dodać do nich jakiś test jednostkowy. Moglibyście napisać mi jakiś przykład do tego przypadku?

Mam 27 testow w tym jeden modelu cała reszta to requests i testowanie przy pomocy sporka to jakies 15 sek.
Oto jak testuję teraz tą akcję.

[code=ruby]#spec/request/mew_ad_spec.rb
require ‘spec_helper’

describe “New ad specs” do
before(:all) do
@ads = Array.new(3) { Ad.sham!(:advertiser_id => 1, :verification_date => Time.now) }
Category.sham!
end

describe “On the root_path” do
it “listing all ads” do
visit root_path
page.should have_selector(".title", :text => “Lista ogłoszeń”)
page.should have_selector(".ad", :count => 3)
@ads.each do |ad|
page.should have_css(".ad", :text => ad.title )
end
end

it "create ad by advertiser who is not in database" do
  visit root_path
  click_on "Dodaj ogłoszenie"
  fill_in 'ad_title', :with => 'Nerka do sprzedania'
  fill_in 'ad_ad_content', :with => 'sprzedam nieswoja nerke'
  fill_in 'ad_name', :with => 'Czesio'
  fill_in 'Kategoria', :with => '1'
  fill_in 'ad_email', :with => 't@t6.pl' 
  fill_in 'ad_price', :with => '9,76'
  click_on 'Dodaj ogłoszenie'
  current_path.should eq(root_path)
  flash_notice!("Ogłoszenie przekazane do potwierdzenia emaila!")
end

it "create ad by adveritiser who is in database" do
  adv = Advertiser.sham!
  visit root_path
  click_on "Dodaj ogłoszenie"
  fill_in 'ad_title', :with => 'Nerka do sprzedania'
  fill_in 'ad_ad_content', :with => 'sprzedam nieswoja nerke'
  fill_in 'ad_name', :with => adv.name
  fill_in 'Kategoria', :with => '1'
  fill_in 'ad_email', :with => adv.email 
  fill_in 'ad_price', :with => '9,76'
  click_on 'Dodaj ogłoszenie'
  flash_notice!("Ogłoszenie przekazane do weryfikacji!")
end

end
end[/code]

  1. Te 3 Ad-y potrzebne są Ci tylko w pierwszym teście a tworzą się przed każdym.
  2. Zrób sobie oddzielny spec żeby sprawdzić czy działa Ci nawigacja

visit root_path click_link "Dodaj ogłoszenie" current_page.should == new_ad_path
i nie przechodź całej tej ścieżki w każdym teście.
3. Możesz spróbować mock-ować te modele (ale w tym temacie jestem zielony :P)

[quote=zlw][quote=regedarek]Dostaję jeszcze taki błąd

ad.rb:39: syntax error, unexpected keyword_else, expecting ':' (SyntaxError)

[/quote]
Ale czyjego kodu użyłeś?

@paneq w Twoim kodzie był chyba błąd przy if-ie - niepotrzebny “?”. Ano i oczywiście chodziło o self.create_and_verify ;)[/quote]
zlw w twoim kodzie jest chyba jeszcze jeden błąd, kiedy kontroler ma wyrenderować :new dostaję błąd undefined method `model_name’ for NilClass:Class

Tak się dzieje zawsze, czy kiedy nie znajdzie Advertisera? Jak advertiser będzie nil, to tam w sumie może się dziać. Pytanie jeszcze jak masz attr_accessible (czy możesz przekazać advertisera [cały obiekt] jako parametr). Pokaż całość aktualnego kodu :slight_smile:

[code=ruby]#ad.rb
attr_accessible :title, :name, :phone_number, :email, :advertiser_id, :ad_content, :token, :verification_date, :category_id, :price, :display_counter

def self.create_and_verify(params)
advertiser = Advertiser.find_by_email(params[:email])
ad = new(params, advertiser: advertiser)

return false unless ad.save

if advertiser
  :awaiting_verification
else
  AdMailer.ad_token(ad).deliver
  :awaiting_email_confirmation
end

end
#ads_controller.rb
def create
if msg = Ad.create_and_verify(params[:ad])
flash.notice = t(“ad.create.#{msg}”)
redirect_to root_path
else

oczywiscie kiedy wstawie @ad = Ad.new(params[:ad]) działa, natomiast nie wyświetlają mi się błędy walidacji, mam je w locales ustawione

  render :new
end

end[/code]
Przy wpisanym “advertajserze” :slight_smile: też jest błąd

Parameters: {"utf8"=>"✓", "authenticity_token"=>"xOEpdw6F6UJpPVYCi/ucj6fZYvsPC/T2/E00qyq+33g=", "ad"=>{"title"=>"", "price"=>"", "category_id"=>"", "name"=>"", "email"=>"czesio@agh.pl", "phone_number"=>"", "ad_content"=>""}, "commit"=>"Dodaj ogłoszenie"} Category Load (0.2ms) SELECT "categories".* FROM "categories" ORDER BY (case when categories.ancestry is null then 0 else 1 end), categories.ancestry, created_at Advertiser Load (0.2ms) SELECT "advertisers".* FROM "advertisers" WHERE "advertisers"."email" = 'czesio@agh.pl' LIMIT 1

[quote=regedarek][code=ruby]#ad.rb
attr_accessible :title, :name, :phone_number, :email, :advertiser_id, :ad_content, :token, :verification_date, :category_id, :price, :display_counter

def self.create_and_verify(params)
advertiser = Advertiser.find_by_email(params[:email])
ad = new(params, advertiser: advertiser)

return false unless ad.save

if advertiser
  :awaiting_verification
else
  AdMailer.ad_token(ad).deliver
  :awaiting_email_confirmation
end

end
#ads_controller.rb
def create
if msg = Ad.create_and_verify(params[:ad])
flash.notice = t(“ad.create.#{msg}”)
redirect_to root_path
else

oczywiscie kiedy wstawie @ad = Ad.new(params[:ad]) działa, natomiast nie wyświetlają mi się błędy walidacji, mam je w locales ustawione

  render :new
end

end[/code]
Przy wpisanym “advertajserze” :slight_smile: też jest błąd

Parameters: {"utf8"=>"✓", "authenticity_token"=>"xOEpdw6F6UJpPVYCi/ucj6fZYvsPC/T2/E00qyq+33g=", "ad"=>{"title"=>"", "price"=>"", "category_id"=>"", "name"=>"", "email"=>"czesio@agh.pl", "phone_number"=>"", "ad_content"=>""}, "commit"=>"Dodaj ogłoszenie"} Category Load (0.2ms) SELECT "categories".* FROM "categories" ORDER BY (case when categories.ancestry is null then 0 else 1 end), categories.ancestry, created_at Advertiser Load (0.2ms) SELECT "advertisers".* FROM "advertisers" WHERE "advertisers"."email" = 'czesio@agh.pl' LIMIT 1
[/quote]
spróbuj może:

[code=ruby]#ad.rb
attr_accessible :title, :name, :phone_number, :email, :advertiser_id, :ad_content, :token, :verification_date, :category_id, :price, :display_counter

def self.create_and_verify(params)
advertiser = Advertiser.find_by_email(params[:email])
ad = new(params, advertiser_id: advertiser.try(:id)) # dzięki #try(:id) nie rzuci wyjątkiem jeżeli advertiser jest nil-em, tylko zwróci nil

return false unless ad.save

if advertiser
  :awaiting_verification
else
  AdMailer.ad_token(ad).deliver
  :awaiting_email_confirmation
end

end[/code]

niestety nadal to samo ale kod paneqa działa narazie go stosuję.

[code=ruby]Rendered ads/new.html.haml within layouts/application (1.0ms)
Completed 500 Internal Server Error in 63ms

ActionView::Template::Error (undefined method model_name' for NilClass:Class): 1: - title "Dodaj ogłoszenie" 2: 3: .ads 4: = simple_form_for @ad do |f| 5: =f.input :title, :label=>"Tytuł", :hint=>"Maksymalnie 50 znaków" 6: =f.input :price, :label=>"Cena" 7: =f.input :category_id, :label=>"Kategoria" , :hint=>"Możesz wpisać nr kategori ręcznie, lub wybrać z menu poniżej." app/views/ads/new.html.haml:4:in_app_views_ads_new_html_haml__253511790_88556520’
app/controllers/ads_controller.rb:20:in `create’[/code]

mm… ale to jest widok dla #new. W new stosuj po prostu @ad = Ad.new, dopiero w #create ten kod który podałem

[code]#ads_controller.rb
def create
if msg = Ad.create_and_verify(params[:ad])
flash.notice = t(“ad.create.#{msg}”)
redirect_to root_path
else

oczywiscie kiedy wstawie @ad = Ad.new(params[:ad]) działa, natomiast nie wyświetlają mi się błędy walidacji, mam je w locales ustawione

render :new
end
end[/code]
Błąd jest tylko w przypadku kiedy formularz jest pusty wtedy zostaje wyrenderowany od nowa,
w akcji new mam oczywiście @ad = Ad.new.

Jeśli robisz render :new
to kod w akcji new nie zostaje wykonany jest tylko renderowany widok. Do widoku zostają przekazane zmienne instancji a w Twoim przypadku metoda create nie tworzy żadnych zmiennych instancji, więc @ad w formie jest nilem. Żeby ten kod zadziałał powinno wyglądać to mniej więcej tak

[code=ruby]#ad.rb
attr_accessible :title, :name, :phone_number, :email, :advertiser_id, :ad_content, :token, :verification_date, :category_id, :price, :display_counter, :message
def self.create_and_verify(params)
advertiser = Advertiser.find_by_email(params[:email])
ad = new(params, advertiser: advertiser)

return ad unless ad.save

if advertiser
  ad.message = :awaiting_verification
else
  AdMailer.ad_token(ad).deliver
  ad.message = :awaiting_email_confirmation
end
ad

end
#ads_controller.rb
def create
@ad = Ad.create_and_verify(params[:ad])
if @ad.valid?
flash.notice = t(“ad.create.#{@ad.message}”)
redirect_to root_path
else

oczywiscie kiedy wstawie @ad = Ad.new(params[:ad]) działa, natomiast nie wyświetlają mi się błędy walidacji, mam je w locales ustawione

  render :new
end

end[/code]
Co nadal niestety wygląda nie najlepiej :slight_smile: