Ошибка 500 при развертывании приложения в Heroku - PullRequest
1 голос
/ 03 января 2012

При попытке развернуть приложение в Heroku появляется ошибка 500 (на моем локальном хосте все работает нормально). Не уверен, почему это происходит.

Как я могу это исправить? Подробности ошибок ниже ...

Сведения об ошибке

2012-01-03T10:33:49+00:00 app[web.1]: Started GET "/" for 

2012-01-03T10:33:49+00:00 app[web.1]:   Processing by PagesController#home as HTML
2012-01-03T10:33:49+00:00 app[web.1]: 
2012-01-03T10:33:49+00:00 app[web.1]: Completed   in 15ms
2012-01-03T10:33:49+00:00 app[web.1]: 
2012-01-03T10:33:49+00:00 app[web.1]:   app/controllers/pages_controller.rb:7:in `home'
2012-01-03T10:33:49+00:00 app[web.1]: ActiveRecord::StatementInvalid (PGError: ERROR:      syntax error at or near "["
2012-01-03T10:33:49+00:00 app[web.1]: : SELECT     "posts".* FROM       "posts"  WHERE        (user_id IN ([]) OR user_id = 2) ORDER BY  posts.created_at DESC LIMIT 30 OFFSET 0):
2012-01-03T10:33:49+00:00 app[web.1]: 
2012-01-03T10:33:49+00:00 app[web.1]: LINE 1: ...sts".* FROM       "posts"  WHERE       (user_id IN ([]) OR use...
2012-01-03T10:33:49+00:00 app[web.1]:             

Контроллер страниц

class PagesController < ApplicationController

def home
  @title = "Home"
  if signed_in?
      @post = Post.new
      @feed_items = current_user.feed.paginate(:page => params[:page])
  end
end

Модель пользователя

class User < ActiveRecord::Base

has_many :posts, :dependent => :destroy

has_many :relationships, :foreign_key => "follower_id",
:dependent => :destroy
has_many :reverse_relationships, :foreign_key => "followed_id",
:class_name => "Relationship",
:dependent => :destroy

has_many :following, :through => :relationships, :source => :followed
has_many :followers, :through => :reverse_relationships, :source => :follower

attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation

email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

validates :name,     :presence => true,
                     :length => { :maximum => 50 }

validates :email,    :presence => true,
                     :format => { :with => email_regex },
                     :uniqueness => { :case_sensitive => false}

validates :password, :presence     => true,
                     :confirmation => true,
                     :length       => { :within => 6..40 }

before_save :encrypt_password

def has_password?(submitted_password)
    encrypted_password == encrypt(submitted_password)
end

def self.authenticate(email, submitted_password)
    user = find_by_email(email)
    return nil  if user.nil?
    return user if user.has_password?(submitted_password)
end

def self.authenticate_with_salt(id, cookie_salt)
    user = find_by_id(id)
    (user && user.salt == cookie_salt) ? user : nil
end

def following?(followed)
    relationships.find_by_followed_id(followed)
end

def follow!(followed)
    relationships.create!(:followed_id => followed.id)
end

def unfollow!(followed)
    relationships.find_by_followed_id(followed).destroy
end

def feed
    Post.from_users_followed_by(self)
end

private

def encrypt_password
    self.salt = make_salt unless has_password?(password)
    self.encrypted_password = encrypt(password)
end

def encrypt(string)
    secure_hash("#{salt}--#{string}")
end

def make_salt
    secure_hash("#{Time.now.utc}--#{password}")
end

def secure_hash(string)
    Digest::SHA2.hexdigest(string)
end

end

Почтовая модель

class Post < ActiveRecord::Base
attr_accessible :content

belongs_to :user

validates :content, :presence => true, :length => { :maximum => 140 }
validates :user_id, :presence => true

default_scope :order => 'posts.created_at DESC'

scope :from_users_followed_by, lambda { |user| followed_by(user) }

def self.from_users_followed_by(user)
  following_ids = user.following_ids
  where("user_id IN (#{following_ids}) OR user_id = ?", user)
end

private

def self.followed_by(user)
  following_ids = %(SELECT followed_id FROM relationships
        WHERE follower_id = :user_id)
  where("user_id IN (#{following_ids}) OR user_id = :user_id",
       { :user_id => user })
end
end

Ответы [ 2 ]

3 голосов
/ 03 января 2012

Это проблема кода, а не проблема Heroku.

Проблема заключается в Post.from_users_followed_by(self) в вашей модели пользователя.Что бы это ни содержало, оно не является дружественным к Postgres или не защищено от нулевых значений.

1 голос
/ 05 января 2012

Ваша проблема здесь:

def self.from_users_followed_by(user)
  following_ids = user.following_ids
  where("user_id IN (#{following_ids}) OR user_id = ?", user)
  #------------------^^^^^^^^^^^^^^^^
end

Ваш following_ids будет массивом, и когда вы "#{array}", вы получите такие вещи, как [] и [11, 23, 42].Таким образом, where будет выглядеть примерно так:

where("user_id IN ([]) OR user_id = ?", user)
where("user_id IN ([11, 23, 42]) OR user_id = ?", user)

, ни один из них не содержит допустимого SQL.Некоторые базы данных могут игнорировать случайные скобки, но PostgreSQL этого не сделает.

Вам необходимо внести два изменения:

  1. Не включать user_id IN (...) вообще, если following_ids пусто,Выполнение c in () не является допустимым SQL, поэтому вы не хотите этого делать.Опять же, некоторые базы данных мягки и снисходительны, PostgreSQL (к счастью) не относится ни к одной из этих вещей.
  2. Не используйте простую интерполяцию строк для предоставления значений для вашего IN;в этом отношении, вообще не используйте строковую интерполяцию для своего SQL (если нет абсолютно никакого другого пути, и это редко): мы не пишем PHP в 1999 году, мы должны знать лучше сейчас.К счастью для вас (и для всех нас), AR сделает все правильно, если вы передадите ему массив для значения заполнителя.

Примерно так должно работать лучше:

def self.from_users_followed_by(user)
  following_ids = user.following_ids
  if(following_ids.empty?)
    where('user_id = ?', user)
  else
    where('user_id in (?) or user_id = ?', following_ids, user)
  end
end

Вы также можете сделать это так:

def self.from_users_followed_by(user)
  following_ids = user.following_ids
  if(following_ids.empty?)
    where('user_id = ?', user)
  else
    following_ids.push(user.id)
    where('user_id in (?)', following_ids
  end
end

или, мой любимый, вот так:

def self.from_users_followed_by(user)
  where('user_id in (?)', user.following_ids + [user.id])
end
...