如何处理Rails中的eval nil问题

时间:2017-06-27 18:45:57

标签: ruby-on-rails elasticsearch amazon-s3 eval ruby-on-rails-5

我在生产环境中面临一个非常讨厌的错误,这引起了一些混乱。我增加了对生产的记录以缩小问题范围,现在能够在我们的本地环境中重现它。因此,我们在Ubuntu机器上运行Rails 5。该应用程序使用ElasticSearch 5.4,我们将图像存储在Amazon S3上。

处理:用户可以上传图片。 Elasticsearch中有一个用户索引,它还将信息存储到相关的Photo模型中。

问题是指用户上传照片后,有时会在索引页面或详细用户页面上出现错误,其中照片以某种方式被访问。并且要显示的结果不是从数据库读取的,而是Elasticsearch。

解决方法(不是一个)。一旦索引被重新导入,错误就不再发生了 - 最初让我相信它与ElasticSearch有关。

用户模型

class User < ApplicationRecord
      include UserSearchable

  extend FriendlyId
  require "redis"
  friendly_id :slug_candidates, use: :slugged

  has_many :photos

  after_update { self.photos.each(&:touch) }

  ...

用户可搜索的关注

模块UserSearchable       扩展ActiveSupport :: Concern

  included do
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks

    index_name Rails.application.class.parent_name.underscore
    document_type self.name.downcase

    settings index: { number_of_shards: 1 } do
      mapping dynamic: false do
        indexes :description, analyzer: 'english'
        indexes :tagline, analyzer: 'english'
        indexes :username
        ...
      end
    end

    after_touch() { __elasticsearch__.index_document }

    def as_indexed_json(_options = {})
      self.as_json(
          except: [:email, :lat, :lng, :status, :termsofuse, :v_code],
          include: {
              photos: { only: [:name, :caption, :active, :image_data, :downloadable, :uploader_id, :public] },
      ).merge(
          location: {lat: lat.to_f, lon: lng.to_f},
          age: birthday.nil? ? 18 : ((Date.today - birthday.to_date) / 365.25).floor
      )
    end

    def home_search(searcher, order = nil, how_many = nil)
      how_many = 400 unless how_many.is_a?(Integer)
      order = 1 unless order.is_a?(Integer)

      if self.radius < 30
        use_radius = 30
      else
        use_radius = self.radius
      end

      search_definition = Jbuilder.encode do |json|
        json.sort do
          if order == 1
            json.array! [{'_geo_distance' => { :location => {:lat => lat, :lon => lng} }}, '_score']
          else
            json.array! ['_score', {'_geo_distance' => { :location => {:lat => lat, :lon => lng} }}]
          end
        end
        json.query do
          json.bool do
            json.filter do
              json.bool do
                json.must do
                  json.array! [:geo_distance => { :distance => use_radius, :unit => "mi", :location => {:lat => self.lat, :lon => self.lng}, :boost => 5.0}]
                end
                ...
                unless searcher.id.nil?
                  json.must_not do
                    json.array! [ {:term => { 'id' => self.id }} ]
                  end
                end
              end
            end
            ...
          end
        end
        # json.size how_many
      end


      self.class.__elasticsearch__.search(search_definition)
    end
  end
end

照片模型

class Photo < ApplicationRecord
  include ImageUploader[:image]
  include ActiveModel::Validations

  acts_as_taggable

  before_create :set_name

  belongs_to :user, touch: true

  after_update { self.user(&:touch) }

  private

    def set_name
      self.name = "Photo"
    end
end

在控制台中测试问题:

此处,这是问题的。如果我评价这张照片有时它是零,有时它不是!我无法弄清楚为什么?如果我在控制台上运行此命令可以说10次,那么10次中只有2次。这就是当生产系统脱离其轨道并且向用户呈现错误时。由于系统是内联网和新系统,我们实际上向用户显示例外情况(所以不要因为错误的异常处理而感到警惕 - 如果你不清楚,用户就不会说出一件事;)

>> eval(user.photos.sample.image_data)[:small][:id]
=> "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
>> eval(user.photos.sample.image_data)[:small][:id]
!! #<NoMethodError: undefined method `[]' for nil:NilClass>

追加追踪:

    >> Settings.s3 + eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>
    >> eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> 
    => nil
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>
    >> user.photos.sample.image_data
    => "{\"original\":{\"id\":\"photo/47/image/original-114c9db755b25afe0398f5b25aed5bef.jpg\",\"storage\":\"store\",\"metadata\":{\"size\":61357,\"filename\":\"London-Escort-Angelina (5).jpg\",\"mime_type\":\"image/jpeg\",\"width\":500,\"height\":500}},\"large\":{\"id\":\"photo/47/image/large-c3985d412ee05495594caa659feca371.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":\"shrine-s320170627-29702-17km6c5.jpg\",\"size\":61356,\"mime_type\":\"image/jpeg\",\"width\":500,\"height\":500}},\"small\":{\"id\":\"photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg\",\"storage\":\"store\",\"metadata\":{\"filename\":\"shrine-s320170627-29702-ouo63f.jpg\",\"size\":25642,\"mime_type\":\"image/jpeg\",\"width\":300,\"height\":300}}}"
    >> user.photos.sample.image_data[:small]
    !! #<TypeError: no implicit conversion of Symbol into Integer>
    >> eval(user.photos.sample.image_data)[:small]
    => {:id=>"photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg", :storage=>"store", :metadata=>{:filename=>"shrine-s320170627-29702-ouo63f.jpg", :size=>25642, :mime_type=>"image/jpeg", :width=>300, :height=>300}}
    >> eval(user.photos.sample.image_data)[:small][:id]
    => "photo/47/image/small-2cd0928d02826f0614086a01ee97ef32.jpg"
    >> eval(user.photos.sample.image_data)[:small][:id]
    !! #<NoMethodError: undefined method `[]' for nil:NilClass>

非常感谢任何帮助!!!

2 个答案:

答案 0 :(得分:0)

您的结果有所不同,因为您使用sample方法,从user.photos中选择一个随机元素。

为防止出现undefined method [] for nil:NilClass错误,您可以将&.dig用于ruby&gt; = 2.3或try(如果更少)

  

nil&amp; .dig(:small,:id)

     

=&GT;零

     

nil.try(:dig,:small,:id)

     

=&GT;零

答案 1 :(得分:0)

因此,我可以通过在上传或删除照片时重新索引更新的用户文档来解决问题(workaround-ish)。之前忘了破坏部分。由于必须在ES中删除整个记录并重新编制索引,但是流量很低并且暂时可行,因此它看起来并不正确,因为它很麻烦。如果我弄清楚这个问题,我会回到这个问题。