Rails 3.1 — перед ошибкой фильтра и базы данных

#ruby-on-rails-3 #lazy-loading #before-filter

#ruby-on-rails-3 #отложенная загрузка #перед фильтром

Вопрос:

У меня возникли некоторые проблемы с отложенной загрузкой, я в этом уверен… может быть, вы могли бы указать мне, где я потерпел неудачу.

 def setup_guild
 if params[:guild]
  @guild = Guild.where(:short_name => params[:guild].upcase).first
  if @guild.nil?
    puts "no guild with short name #{params[:guild]} found"
    redirect_to root_path 
  else
    @title = t "layout.guild_title", :guild_name =>  (@guild.name).capitalize
  end
 else
  @guild = nil
 end
end
  

Который вызывается в ApplicationController как фильтр перед.
Сначала я использовал Guild.find_with_short_name , но у меня был такой же тупой ответ, как и сейчас… это :

 undefined method `capitalize' for nil:NilClass
app/controllers/application_controller.rb:29:in `setup_guild'
  

То есть, вы бы догадались, что там есть строка @title.

Дело в том, что если я попробую что-то подобное в консоли, я получу ожидаемый результат

 ruby-1.9.2-p0 > guild = Guild.where(:short_name => "ICPT").first
  Guild Load (0.5ms)  SELECT "guilds".* FROM "guilds" WHERE "guilds"."short_name" = 'ICPT' LIMIT 1
 => #<Guild id: 2, name: "Inception", detail: "Inception Guild", game_server_id: 2, created_at: "2011-10-30 17:41:19", updated_at: "2011-10-30 17:41:19", short_name: "ICPT"> 
ruby-1.9.2-p0 > guild.name.capitalize
 => "Inception" 
  

Более того, если я добавлю что-то вроде «puts @guild.inspect» сразу после выборки, заглавные буквы работают нормально, поэтому я думаю, что это сбой отложенной загрузки.

Я был бы рад получить представление о том, как решить эту глупую проблему… Я действительно не хочу, чтобы в моем коде не было @guild.inspect, я считаю, что это неубедительное решение…

Спасибо!

@PanayotisMatsinopoulos В соответствии с просьбой, вот таблица гильдии :

 create_table "guilds", :force => true do |t|
    t.string   "name"
    t.text     "detail"
    t.integer  "game_server_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "short_name"
  end
  

@PanayotisMatsinopoulos Вот и ты, мой друг 😉 Я все еще должен i18n это

 #encoding: utf-8
class Guild < ActiveRecord::Base
  belongs_to :game_server
  has_one :game, :through => :game_server
  has_many :announcement, :dependent => :destroy
  validates_presence_of :name, :on => :create, :message => "dois avoir un nom"
  validates_presence_of :detail, :on => :create, :message => "dois avoir une description"
  validates_presence_of :game, :on => :create, :message => "dois appartenir a un jeu"
  validates_presence_of :short_name, :on => :create, :message => "dois avoir un acronyme"
  validates_uniqueness_of :short_name, :on => :create, :message => "est deja utilise"
  validates_length_of :short_name, :within => 3..5, :on => :create, :message => "dois faire entre 3 et 5 caracteres"
  validates_exclusion_of :short_name, :in => %w( users admin guilds events loots sessions characters games password), :on => :create, :message => "ne peux pas utilisé se genre d'acronyme"
  validates_uniqueness_of :name, :on => :create, :message => "est deja utilise"

  has_many :guild_mates, :dependent => :destroy
  has_many :guild_ranks, :dependent => :destroy
  has_many :guild_settings, :dependent => :destroy
  has_many :events, :dependent => :destroy
  has_many :characters, :dependent => :destroy

  before_validation :short_name_check ,:on => :create

  after_create :guild_basic_settings

  def guild_basic_settings
    GuildSettingType.all.each do |grst|
      grs = GuildSetting.create do |g|
        g.guild_id = self.id
        g.guild_setting_type_id = grst.id
        g.value = "false"
      end    
    end
    set_setting(["setting_allow_basic_access_for_public","setting_allow_application",
      "setting_allow_event_read_for_public","setting_allow_announcement_read_for_public"],"true")
  end

  def set_setting(setting,value)

    if setting.class == Array
      setting.uniq!
      setting.each do |ar|
        set_setting(ar,value)
      end
    else
      grs = nil
      if setting.class == String
        grs = guild_settings.includes(:guild_setting_type).where(:guild_setting_type => {:name => setting}).first
        return if grs.nil?
      else
        grs = guild_rank_settings.where(:guild_setting_type => setting)
        return if grs.nil?
      end

      grs.value = value
      grs.save
    end
  end

  def short_name_check
    short_name.upcase! if short_name
  end

  def full_name
    "#{name.capitalize} - #{game_server.name}"
  end

  def characters_for_user(user)
    characters.where(:user_id => user.id)
  end

  def method_missing(method,*args)
    check = method.to_s.split("_")
    if(args.count == 0)
      if check[0] == "setting"
         grs = guild_settings.joins(:guild_setting_type).where(:guild_setting => { :guild_setting_types => {:name => method.to_s}}).first
          unless grs.nil?
            return grs.value == "true" ? true : false
          else
            raise "Guild > Method Missing > unknown setting : #{method.to_s}"
          end
      end
    end
  end

end
  

Редактировать: я только что увидел, что я не пропустил супер-метод… может ли это быть проблемой?

Комментарии:

1. Почему у вас есть :guild_name => (@guild.name).capitalize , а нет :guild_name => @guild.name.capitalize ? (Возможно, это не проблема, но я просто спрашиваю)

2. Ну, это было так, как вы спрашивали раньше, я просто пробовал альтернативы … ^^

3. Я могу только догадываться, что ваш запрос возвращает запись с name нулевым значением. Я не могу найти другого очевидного объяснения. Поставьте inspect перед, чтобы узнать, верно это или нет.

4. >> Более того, если я добавлю что-то вроде «puts @guild.inspect» сразу после выборки, заглавные буквы работают нормально, поэтому я думаю, что это сбой отложенной загрузки.

5. Можете ли вы опубликовать свою Guild модель?

Ответ №1:

Хорошо, похоже, проблема заключалась в моей реализации method_missing. В нем отсутствовал суперзвонок… Теперь, когда он был восстановлен, все работает нормально. неудивительно.

Спасибо @PanayotisMatsinopoulos за вашу помощь 🙂 (также спасибо за хороший ночной сон ; p)

Ответ №2:

вы также должны проверить, равно ли name nil:

 if @guild.nil? || @guild.name.nil?
  

Комментарии:

1. Думаю, я мог бы … тем не менее, я нахожу это маловероятным (я проверяю наличие имени при создании… тем не менее, это может помочь …)

2. Пытался, он обнаружил проблему, но не решил ее для записей, поле имени которых заполнено, но не загружено

Ответ №3:

Верно. method_missing должен быть вызван super в конце. Но я не уверен, что ваша проблема существует. Это может быть. Возможно, это не так.

С другой стороны, позвольте мне рассказать кое-что, что, по моему мнению, имеет больше шансов стать вашей проблемой. Это тот факт, что вы выполняете свою проверку presence name только :on => :create для of . Это означает, что обновление объекта Guild , который не содержит name , пройдет проверку и будет сохранен в базе данных без проблем. Тогда вы setup_guild обязательно выдадите ошибку:

 undefined method `capitalize' for nil:NilClass
app/controllers/application_controller.rb:29:in `setup_guild'
  

т. е. Ошибка, с которой началось это обсуждение.

Следовательно, мое предложение состоит в том, чтобы удалить ваше :on => :create условие при проверке name . (кстати … я предлагаю вам удалить его из всех ваших проверок, если вы не знаете, что делаете)

Но тогда я не могу доказать, что это была ваша проблема в первую очередь. Я просто привожу здесь свой совет, а не мой положительный ответ в качестве решения вашей проблемы.

Комментарии:

1. Привет @PanayotisMatsinopoulos, проблема заключалась в method_missing. Что касается проблемы проверки, которую вы выделяете, на самом деле эти атрибуты не предназначены для обновления, поэтому это не должно быть проблемой. Но, как можно было бы сказать, случается всякое 😉 поэтому я последую вашему совету и на всякий случай удалю инструкцию :on . В любом случае спасибо за вашу помощь!

2. @Kluthen57 Хорошо, спасибо за отзыв. Если вы все еще считаете, что мой ответ был полезным, я был бы признателен за голосование, даже если он не выбран в качестве ответа на ваш вопрос. Голосование означает «Этот ответ полезен». В любом случае спасибо.

3. не могу проголосовать за вас, извините, у меня недостаточно репутации для этого: x