2016-11-13 11 views
0

Я использую FriendlyID, и он создает пул, основанный на некоторых атрибутах записи при создании.Как разрешить проверку AR до расширения модуля на моей модели?

extend FriendlyId 
    friendly_id :name_and_school, use: :slugged 

    def name_and_school 
    "#{first_name} #{last_name} #{school.name}" 
    end 

У меня также есть следующие на моей модели:

validates :first_name, :last_name, presence: true 
    validates_associated :school, presence: true 

Однако, когда я иду, чтобы проверить эту проверку и отправить форму с пустым значением для first_name, last_name and school, я получаю следующее сообщение об ошибке:

Position Load (0.8ms) SELECT "positions".* FROM "positions" WHERE 1=0 
    (0.8ms) BEGIN 
    (0.6ms) ROLLBACK 
Completed 500 Internal Server Error in 51ms (ActiveRecord: 11.7ms) 



NoMethodError - undefined method `name' for nil:NilClass: 
    app/models/profile.rb:79:in `name_and_school' 
    friendly_id (5.1.0) lib/friendly_id/slugged.rb:295:in `should_generate_new_friendly_id?' 
    friendly_id (5.1.0) lib/friendly_id/slugged.rb:304:in `set_slug' 

Так что понятно, что он наносит удар по этому методу name_and_school, даже до того, как он проверит проверки проверки ActiveRecord.

Если он сначала проверяет проверку, он не будет генерировать эту ошибку, он просто перезагрузит страницу соответствующими ошибками.

Так как я могу исправить это и убедиться, что пул FriendlyID генерируется только в том случае, если все проверки проходят?

Edit 1

Так что я пытался настаивать, что name_and_school только возвращает правильную строку, если значения присутствуют как так:

def name_and_school 
    "#{first_name} #{last_name} #{school.name}" if first_name.present? && last_name.present? && school.present? 
    end 

Это теперь работает для пустых/поврежденных first_name и last_name атрибутов.

Однако, когда я покинул поле школы пустым, теперь он дает мне эту ошибку:

Completed 500 Internal Server Error in 31689ms (Searchkick: 9.5ms | ActiveRecord: 23.6ms) 

NoMethodError - undefined method `name' for nil:NilClass: 
    app/models/profile.rb:139:in `search_data' 
    searchkick (1.4.0) lib/searchkick/index.rb:289:in `search_data' 
    searchkick (1.4.0) lib/searchkick/index.rb:66:in `block in bulk_index' 
    searchkick (1.4.0) lib/searchkick/index.rb:66:in `bulk_index' 
    searchkick (1.4.0) lib/searchkick/index.rb:54:in `store' 
    searchkick (1.4.0) lib/searchkick/logging.rb:28:in `block in store' 
    activesupport (5.0.0.1) lib/active_support/notifications.rb:164:in `block in instrument' 
    activesupport (5.0.0.1) lib/active_support/notifications/instrumenter.rb:21:in `instrument' 
    activesupport (5.0.0.1) lib/active_support/notifications.rb:164:in `instrument' 
    searchkick (1.4.0) lib/searchkick/logging.rb:27:in `store' 
    searchkick (1.4.0) lib/searchkick/index.rb:96:in `reindex_record' 
    searchkick (1.4.0) lib/searchkick/model.rb:113:in `reindex' 
    app/models/profile.rb:146:in `reindex_profile' 

что соответствует этому в моей модели:

after_commit :reindex_profile 

    def search_data 
    { 
     name: name, 
     bib_color: bib_color, 
     height: height, 
     weight: weight, 
     player_type: player_type, 
     school_name: school.name, 
     age: age, 
     position_name: positions.map(&:name) 
    } 
    end 

    def reindex_profile 
    reindex 
    end 

После того, как новый рекорд привержен, он запускает этот обратный вызов - который ожидает действительный атрибут school.

Так что значение nil по-прежнему выходит из проверки validates_associated.

Я даже пытался добавить тот же if заявление метода reindex_profile следующим образом:

def reindex_profile 
    reindex if first_name.present? && last_name.present? && school.present? && bib_color.present? && player_type.present? && age.present? 
    end 

Но это не работает.

Edit 2

После ответа попробовать @ codyeatworld, мы делаем успехи.

Проблема в том, что, хотя я больше не получаю эти ошибки, запись создается, несмотря на то, что validates_associated :school, presence: true не является истинным.

Например, вот пример запроса:

Started POST "/profiles" for ::1 at 2016-11-13 16:32:19 -0500 
Processing by ProfilesController#create as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"skJA+9NB3XhR/JLgQ==", "profile"=>{"avatar"=>#<ActionDispatch::Http::UploadedFile:0x007fbf3b35d9a8 @tempfile=#<Tempfile:/var/folders/0f/hgplttnd7d/T/RackMultipart20161113-16651-1wvdzdx.jpg>, @original_filename="Random-Image.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"profile[avatar]\"; filename=\"Random-Image.jpg\"\r\nContent-Type: image/jpeg\r\n">, "first_name"=>"Random", "last_name"=>"Brown", "dob(3i)"=>"13", "dob(2i)"=>"11", "dob(1i)"=>"1986", "weight"=>"", "height"=>"", "bib_color"=>"", "player_type"=>"player", "position_ids"=>[""], "school_id"=>"", "grade"=>"", "tournament_ids"=>[""], "email"=>"", "cell_phone"=>"", "home_phone"=>"", "grades_attributes"=>{"0"=>{"subject"=>"", "result"=>"", "grade_type"=>"csec", "_destroy"=>"false"}}, "transcripts_attributes"=>{"0"=>{"url_cache"=>"", "_destroy"=>"false"}}, "achievements_attributes"=>{"0"=>{"body"=>"", "achievement_type"=>"academic", "_destroy"=>"false"}}, "videos_attributes"=>{"0"=>{"vimeo_url"=>"", "official"=>"", "_destroy"=>"false"}}, "articles_attributes"=>{"0"=>{"source"=>"", "title"=>"", "url"=>"", "_destroy"=>"false"}}}, "commit"=>"Create Profile"} 
    User Load (1.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]] 
    Role Load (1.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 2]] 
    Role Load (1.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'coach') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 2]] 
    Role Load (1.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'player') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 2]] 
    (1.7ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)) OR ((roles.name = 'coach') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 2]] 
The "mime_type" Shrine metadata field will be set from the "Content-Type" request header, which might not hold the actual MIME type of the file. It is recommended to load the determine_mime_type plugin which determines MIME type from file content. 
    Tournament Load (1.2ms) SELECT "tournaments".* FROM "tournaments" WHERE 1=0 
    Position Load (0.8ms) SELECT "positions".* FROM "positions" WHERE 1=0 
    (0.9ms) BEGIN 
    SQL (2.2ms) INSERT INTO "profiles" ("first_name", "last_name", "dob", "bib_color", "created_at", "updated_at", "player_type", "grade", "home_phone", "cell_phone", "email", "avatar_data") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" [["first_name", "Yashin"], ["last_name", "Brown"], ["dob", Thu, 13 Nov 1986], ["bib_color", ""], ["created_at", 2016-11-13 21:32:19 UTC], ["updated_at", 2016-11-13 21:32:19 UTC], ["player_type", 0], ["grade", ""], ["home_phone", ""], ["cell_phone", ""], ["email", ""], ["avatar_data", "{\"id\":\"83d162a3d33bdc5d2527502e1d423ab3.jpg\",\"storage\":\"cache\",\"metadata\":{\"filename\":\"Random-Image.jpg\",\"size\":61798,\"mime_type\":\"image/jpeg\"}}"]] 
    SQL (2.0ms) INSERT INTO "transcripts" ("profile_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["profile_id", 30], ["created_at", 2016-11-13 21:32:19 UTC], ["updated_at", 2016-11-13 21:32:19 UTC]] 
    Profile Load (3.7ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = $1 LIMIT $2 [["id", 30], ["LIMIT", 1]] 
    (1.6ms) COMMIT 
    (0.9ms) BEGIN 
    SQL (2.6ms) UPDATE "profiles" SET "updated_at" = $1, "avatar_data" = $2 WHERE "profiles"."id" = $3 [["updated_at", 2016-11-13 21:32:19 UTC], ["avatar_data", "{\"id\":\"ec63dcc18ed5d60aa7a6626550f9f9ea.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":\"Random-Image.jpg\",\"size\":61798,\"mime_type\":\"image/jpeg\"}}"], ["id", 30]] 
    (1.3ms) COMMIT 
    Profile Store (311.8ms) {"id":30} 
    Profile Store (32.2ms) {"id":30} 
    Profile Store (26.7ms) {"id":30} 
    Profile Store (18.9ms) {"id":30} 
Redirected to http://localhost:3000/profiles/30 
Completed 302 Found in 530ms (Searchkick: 389.6ms | ActiveRecord: 32.2ms) 

Обратите внимание, что "school_id"=>"", также заметить, что URL теперь profiles/30 (а не URL FriendlyID, что означает, что friendlyID пробкового не выполнить что я и хочу).

Почему эта запись все еще создается, несмотря на мой вызов validates_associated, который у меня есть на модели?

+0

Попробуйте удалить 'Использование:: slugged'? – codyeatworld

+0

Но тогда это не сгенерирует слизню, которую я хочу на действительные записи, нет? – marcamillion

+0

Вы правы, прошло некоторое время, так как я использовал friendly_id. Этот ответ может объяснить, почему: http://stackoverflow.com/a/36478639/6742278. Я думаю, вам нужно сказать friendlyId, чтобы генерировать слизню, только если школа присутствует. – codyeatworld

ответ

1

Я думаю, что вы ищете should_generate_new_friendly_id.

def should_generate_new_friendly_id? 
    first_name.present? && last_name.present? && school.present? 
end 

FriendlyId попытается создать слизню, если эти условия выполнены.

Я думаю, что оскорбительная линия в поиске - это атрибут .

def search_data 
    { 
    name: name, 
    bib_color: bib_color, 
    height: height, 
    weight: weight, 
    player_type: player_type, 
    # school_name: school.name, 
    school_name: (school.present? ? school.name : nil), 
    age: age, 
    position_name: positions.map(&:name) 
    } 
end 

Я предполагаю, что вы хотите, чтобы проверить наличие school. В методе validates_associated будут выполняться проверки для объекта/модели school. Он не проверяет наличие school_id.

validates :first_name, :last_name, :school_id, presence: true 
# Remove validates_associated :school, presence: true 

Я думаю, вы также можете опустить _id:

belongs_to :school 
validates :school, presence: true 
+0

Хорошо ... это делает то же самое, что и добавление 'if first_name.present? && ... 'Однако проблема, с которой я столкнулся, - это еще один модуль - searchkick - делать то же самое, что и FriendlyID. Мысли там? Другими словами, я попробовал ваш ответ, и я все еще получаю ошибку, связанную с «school.name is nil». – marcamillion

+0

Я обновил свой ответ. Трудно сказать, не видя больше моделей/как это связано. – codyeatworld

+0

Хорошо, вы добираетесь туда медленно, но верно. Вам не хватало тернарного оператора, который я добавил - и который работал, в том смысле, что он больше не выбрасывает странную ошибку. Тем не менее, есть что-то еще более странное, что происходит. Запись была создана, хотя 'validates_associated: school, presence: true' недействительна. Я собираюсь обновить вопрос более подробно. – marcamillion