2015-10-31 1 views
0

J'ai un modèle Restaurant qui utilise Geocoder pour regrouper la ville, l'état et le voisinage sur un rappel before_validation.méthode indéfinie `nom 'pour nil: NilClass pour slug personnalisé

class Restaurant < ActiveRecord::Base 
    # attrs: :name, :address, :city_id, :neighborhood_id 

    ... 

    before_validation :geocode 

    geocoded_by :address do |obj,results| 
    if geo = results.first 
     obj.city = City.where(name: geo.city).first_or_create 
     obj.city.update_attributes(state: State.where(name: geo.state).first_or_create) 

     obj.neighborhood = Neighborhood.where(name: geo.neighborhood).first_or_create 
     obj.neighborhood.update_attributes(city: City.where(name: geo.city).first_or_create) 

     obj.longitude = geo.longitude 
     obj.latitude = geo.latitude 
    end 
    end 
end 

Dans mon modèle City je l'ai mis en place une limace personnalisée qui utilise le nom de la ville et le nom de l'Etat qu'il appartient.

class City < ActiveRecord::Base 
    # attrs :name, state_id 

    belongs_to :state 

    friendly_id :state_slug, use: :slugged 

    def state_slug 
    "#{name} #{state.name}" 
    end 
end 

Chaque fois que je créer un nouveau restaurant, je suis l'erreur:

undefined method `name' for nil:NilClass 

def state_slug 
    "#{name} #{state.name}" 
end 

parce qu'il n'y a Naturellement pas une ville ou un État qui n'a pas encore persisté à la base de données. Je me demande comment puis-je configurer mon rappel pour que cela fonctionne?

+0

Avez tu essayes? '" # {nom} # {ville.try (: nom)} "'? Il s'assurera que ça n'échoue pas quand 'ville' est' néant ' –

+0

Ouais mais le problème est que j'ai besoin du nom de la ville. Faire ce que vous avez décrit me donnera '/ houston' au lieu de'/houston-texas'. J'ai besoin de la dernière des deux. –

+0

Vous avez besoin du nom de l'état, pas de la ville –

Répondre

0

Écrivez cette méthode dans votre modèle City. Cela générera un slug lorsque votre identifiant d'état sera changé.

def should_generate_new_friendly_id? 
    new_record? || state_id_changed? 
end 

Et faites ce petit changement à la méthode suivante.

def state_slug 
    "#{name} #{state.name}" if state.present? 
    end 
+0

J'ai besoin de cela sur 'create' cependant. Pas de "mise à jour". –

+0

Cela sera pris en charge par amical lorsque vous créez, vérifiez la première condition new_record ?. Cela rendra cela possible. Avez-vous rencontré un problème en suivant ma solution? Faites-moi savoir que je peux partager. Cette chose peut être faite de plusieurs façons. – Rubyrider

0

La seule façon que je peux penser est d'utiliser inverse_of:

#app/models/state.rb 
class State < ActiveRecord::Base 
    has_many :cities, inverse_of: :state 
end 

#app/models/city.rb 
class City < ActiveRecord::Base 
    belongs_to :state, inverse_of: :cities 
end 

Il n'y a pas beaucoup de documentation à ce sujet; cela signifie essentiellement que vous êtes en mesure d'appeler les données associées dans leurs modèles respectifs, IE city.state (même si state n'est pas enregistré).

Ainsi, si vous configurez un état chaque fois que vous ajoutez une ville (et ils sont associés), vous devriez pouvoir appeler les éléments suivants (validation):

#app/models/city.rb 
class City < ActiveRecord::Base 
    belongs_to :state, inverse_of: :cities 
    validates :state, presence: true 

    friendly_id :state_slug, use: :slugged 

    private 

    def state_slug 
    "#{name} #{state.name}" 
    end 
end 
+0

Il semble que 'inverse_of' n'a pas fait l'affaire. Toujours à gauche avec la même erreur. –