Walidacja i relacja has_many

Witam wszystkich!
Ponieważ aktualnie szukam pracy, mam dużo czasu i postanowiłem poznać Ruby on Rails.
Dla ćwiczeń wymyśliłem aplikację, w której wpisuje najczęstsze stawiane przez pracodawców wymagania, znajomości (Knowledges), w nich chcę jeszcze dodawać linki do ogłoszeń o pracę, w których dana znajomość jest wymagana. Podawana jest dodatkowo liczba ogłoszeń w której dane wymaganie się pojawiło np: Znajomość css - Poziom znajomości: dobra - Liczba ofert: 5 - linki: http:// …, http:// …
Mam nadzieję, że przybliżyłem co nie co o co chodzi w mojej aplikacji.
A teraz konkrety:
Wchodzę do szczegółów danej znajomości, wpisuję link ale przy próbie zapisu wyskakuje mi błąd

ActiveRecord::RecordInvalid (Validation failed: Name is invalid): …

Jak się z tym uporać?

Kontroler dodawania linków:

[code]class LinksController < ApplicationController
def create
@knowledge = Knowledge.find(params[:knowledge_id])
@links = Link.all
@link = @knowledge.links.create!(params[:link])

if @knowledge.save
  flash[:notice] = 'Dodałeś link do strony!'
  redirect_to @knowledge
end

end
end[/code]
View show.html.erb

[code]…

Liczba ofert: <%=h @knowledge.amount %>

Poziom znajomości: <%= @knowledge.level.name %>

Linki:
<%= render :partial => @knowledge.links %>
<% form_for [@knowledge, Link.new] do |f| %>

<%= f.label :name, "Dodaj link" %> <%= f.text_field :name %>

<%= f.submit "Zapisz" %> <% end %>
.......[/code] knowledge.rb [code]# == Schema Information # Schema version: 20100510095706 # # Table name: knowledges # # id :integer not null, primary key # name :string(255) # amount :integer # level_id :integer # link_id :integer # created_at :datetime # updated_at :datetime # class Knowledge < ActiveRecord::Base has_many :links end[/code] link.rb

[code]# == Schema Information

Schema version: 20100510095706

Table name: links

id :integer not null, primary key

name :string(255)

knowledge_id :integer

created_at :datetime

updated_at :datetime

class Link < ActiveRecord::Base
belongs_to :knowledge
LinkRegex = /\A[http:\]+[www]+.[a-z]+.[a-z]+\z/i
validates_format_of :name, :with => LinkRegex
end[/code]

if @knowledge.save powinieneś zamienić na if @link.save.
Wczytywanie wszystkich linków (@links = Link.all) w akcji create jest niepotrzebne.
Ponadto jeśli teraz decydujemy się na if @link.save, to

@link = @knowledge.links.create!(params[:link])

Powinno być zamienione na

@link = @knowledge.links.build(params[:link])

W Ruby raczej nie używa się CamelCase w przypadku stałych, dlatego LinkRegex → LINK_REGEX.
A błąd walidacji wypluwa może dlatego, że właśnie owy regex jest zły? :wink: Testowałem na rubular.com i nie działa dla http://google.pl

Edit:

Jeśli masz relację one to many, to link_id w modelu Knowledge jest niepotrzebne - dodajesz tylko podobne pole dla modelu z belongs_to.

tak na pierwszy rzut oka, to w tym regexp powinno być chyba http:// (\ backslashem poprzedzasz znaki specjalne jak . czy /)

Takie moje 5gr dot. Regexp.
Aby nie bawić się w \ dla znaków specjalnych to polecam wrzucenie wszystkiego w %r{}

Drugie 5gr., pojawiło się dużo pluginów do walidacji.

I trzecie 5gr. :wink: Polecam prosty sposób.

validates_format_of :uri, :with => URI::regexp(%w(http https))

Dzięki chłopaki. Wszystkie wasze uwagi były/są bardzo przydatne. Już chyba wiem co jest nie tak.
Zamiast ostylowanego boksu z błędami (patrz rysunek), pojawił mi się błąd o którym wspomniałem w moim poprzednim poście czyli ActiveRecord::RecordInvalid (Validation failed: Name is invalid): … Na dole macie cały Trace

C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/validations.rb:1090:in `save_without_dirty!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/dirty.rb:87:in `save_without_transactions!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:182:in `transaction' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:208:in `rollback_active_record_state!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:255:in `create!' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:415:in `create_record' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:433:in `add_record_to_target_with_callbacks' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:415:in `create_record' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:253:in `create!' C:/Users/Leszek/Documents/NetBeansProjects/praca/app/controllers/links_controller.rb:4:in `create' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:1331:in `send' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:1331:in `perform_action_without_filters' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/filters.rb:617:in `call_filters' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue' C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/core_ext/benchmark.rb:17:in `ms' C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/core_ext/benchmark.rb:10:in `realtime' C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/core_ext/benchmark.rb:17:in `ms' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/rescue.rb:160:in `perform_action_without_flash' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/flash.rb:146:in `perform_action' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:532:in `send' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:532:in `process_without_filters' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/filters.rb:606:in `process' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:391:in `process' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/base.rb:386:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/route_set.rb:437:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:87:in `dispatch' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:121:in `_call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:130:in `build_middleware_stack' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:29:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:29:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:9:in `cache' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/query_cache.rb:28:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/connection_pool.rb:361:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/string_coercion.rb:25:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/head.rb:9:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/methodoverride.rb:24:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:15:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/session/cookie_store.rb:93:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/failsafe.rb:26:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `synchronize' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:114:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/reloader.rb:34:in `run' C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:108:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/static.rb:31:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:46:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `each' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/log_tailer.rb:17:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/content_length.rb:13:in `call' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/handler/webrick.rb:50:in `service' C:/Ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service' C:/Ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run' C:/Ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread' C:/Ruby/lib/ruby/1.8/webrick/server.rb:162:in `start' C:/Ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread' C:/Ruby/lib/ruby/1.8/webrick/server.rb:95:in `start' C:/Ruby/lib/ruby/1.8/webrick/server.rb:92:in `each' C:/Ruby/lib/ruby/1.8/webrick/server.rb:92:in `start' C:/Ruby/lib/ruby/1.8/webrick/server.rb:23:in `start' C:/Ruby/lib/ruby/1.8/webrick/server.rb:82:in `start' C:/Ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/handler/webrick.rb:14:in `run' C:/Ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/commands/server.rb:111 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require' C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' script/server:3

Rav na razie zostanę przy swoim bo po twojej sugestii wyskakuje mi błąd o braku szablonu Missing template links/create.erb in view path app/views.
W sumie to kod przerobiłem na swoje potrzeby po obejrzeniu filmiku na stronie http://rubyonrails.org/screencasts (Creating a weblog in 15 minutes with Rails 2)

Sprawdziłem - obie wersje mi działają. Chyba, że chodziło Ci o kwestię standardów. Użyłem akurat takiej nazwy i uznałem ją za poprawną po przestudiowaniu tutorialu na http://www.railstutorial.org/

Chciał bym przy okazji polecić link który to mnie polecił mój kolega. Jest tam sporo gotowych wyrażeń regularnych. Może się komuś przydać: http://regexlib.com/Search.aspx?k=email.

Kolega @rav dobrze zasugerował o zmianę na ‘if @link.save’ oraz na ‘@link = @knowledge.links.build(params[:link])’
A co do błędu to masz właściwy ponieważ warunek nie został spełniony, więc coś musisz dalej zrobić, np. wyświetlenie ‘edit’ lub cokolwiek w czym masz formularz.

Powodzenia w kodowaniu :slight_smile:

Ok zaczynam świrować :slight_smile:
Gdy warunek walidacji jest spełniony, tzn adres linku jest poprawnie wpisany, po kliknięciu na przycisk Dodaj link przekierowywany zostaję na stronę podglądu znajomości wraz z odpowiednim zielonym boxem - ok wspaniale. Natomiast gdy warunek nie został spełniony zostaję przekierowany na tę stronę co poprzednio ale już czerwony box z błędami się nie nie wyświetla. Pomocy, o czym zapomniałem …?

if @link.save flash[:notice] = 'Dodałeś link do strony!' redirect_to @knowledge else redirect_to @knowledge end

bład sam sie do flasha nie doda :slight_smile:
flash[:error] = ‘Link sie nie dodał’

Tzn tak już próbowałem. I działa. I teraz pytanie gdy normalnie dodaję jakiś “knowledge” i zrobię błąd w jakimś polu wyświetla mi się div z id=“errorExplanation”, z tutułem diva “3 errors prohibited this knowledge from being saved” no i listą pół które trzeba poprawić. Dla czego taki div nie pokazuje się gdy zrobię błąd podczas dodawania linku. Czy tak już jest i trzeba użyć flasha? czy ja robię coś źle?

z tego co widze w tym kodzie w pierwszym poście, gdy dodajesz knowledge to w przypadku błędu nie masz redirect a w szablonie knowledge/edit masz zapewne error_messages_for :knowledge, błąd “siedzi” w obiekcie @knowledge i moze byc pokazany. zerknij do rozdziału 8 http://guides.rubyonrails.org/activerecord_validations_callbacks.html
natomiast jesli uzywasz redirect to trzeba ten błąd jakoś przekazac do nastepnego requestu i robi sie to właśnie flashem.