Rails: различное поведение на dev и production - PullRequest
4 голосов
/ 16 марта 2010

Я выполняю работы по обслуживанию сайта Rails, который развернут с использованием Phusion Passenger . Рабочий процесс немного отличается от стандартного трехуровневого рельсовского соглашения о тестировании и разработке; вместо этого существуют две отдельные установки одной и той же кодовой базы, работающие с параллельными базами данных Oracle; сайт разработчика находится на qa.domain.com, а сайт в реальном времени на www.domain.com

Я испытываю различное поведение в следующем фрагменте кода (из файла vendors_controller.rb, который использует AuthenticatedSystem) между двумя средами:

def create
  @user = current_user || User.new(params[:user])
  @registration = Registration.new(params[:registration])

  unless current_user

    @user.user_type = 'vendor'
    @user.active = 1

    if @user.save
      @user.activate!
      @user.has_role 'owner', @user
      @user.has_role 'vendor'
      self.current_user = user = @user

      @registration.active = 1
      @registration.email = @user.email
      @registration.user_id = @user.id
      if @registration.save
        send_confirmation(@user)
        send_solicitations_notifications(@registration) if @registration.notification_desired == true
        redirect_to thank_you_vendors_path
      else
        # THIS BEHAVIOR DIFFERS ACROSS PRODUCTION AND DEVELOPMENT
        @user.destroy
        self.current_user = user = nil
        # END DIFFERENCE
        respond_to do |format|
          format.html { render :action => 'new' }
          format.xml  { render :xml => @registration.errors, :status => :unprocessable_entity }
        end
      end

    else
      respond_to do |format|
        format.html  { render :action => 'new' }
        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
      end
    end
...

Код между комментариями уничтожает только что созданный объект пользователя, если система не смогла создать соответствующую регистрацию. Он отлично работает на сервере разработки, а не на сервере, где объект пользователя упорно висит вокруг базы данных, даже если сохранение регистрации терпит неудачу. Выдвинуть изменения в производство - это просто загрузить файл контроллеров и выполнить touch tmp/restart.txt через оболочку. Две кодовые базы в остальном идентичны; что может быть причиной этой разницы?

Спасибо за внимание!

Джастин

РЕДАКТИРОВАТЬ: Есть несколько различий в production.rb между двумя установками, которые могут помочь диагностировать проблему. На производстве

config.cache_classes = true

# Full error reports are disabled and caching is turned on
config.action_controller.consider_all_requests_local = false
config.action_controller.perform_caching             = true

во время разработки эти три флага устанавливаются в свои обратные значения. Спасибо!

1 Ответ

1 голос
/ 16 марта 2010

Есть несколько вещей, которые вы должны изменить в своем коде:

  1. Вы не используете транзакции
  2. Вы слишком много делаете в контроллере

Сказав, что причина вашей проблемы, вероятно, связана с различиями в среде между производством и разработкой, скорее всего, это:

config.cache_classes = false

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

Чтобы исправить вашу проблему, я бы, скорее всего, переписал действие так:

# using before filters will keep your actions tight
before_filter :cannot_create_user, :if => :signed_in?

def create
  # setup all the objects
  @user = User.new(params[:user])

  @user.user_type = 'vendor'
  @user.active = 1

  @user.has_role 'owner', @user
  @user.has_role 'vendor'

  @registration = @user.registrations.build(params[:registration])
  @registration.active = 1
  @registration.email = @user.email

  # make sure everything is valid before trying to save and activate
  if @user.valid?
    @user.save!  # might not need this if activate calls save!
    @user.activate!

    # this should probably be a sign_in() method... 
    self.current_user = @user

    send_confirmation(@user)
    send_solicitations_notifications(@registration) if @registration.notification_desired?

    redirect_to thank_you_vendors_path
  else
    respond_to do |format|
      format.html { render :action => 'new' }
      format.xml  { render :xml => @registration.errors, :status => :unprocessable_entity }
    end
  end

...
end


protected 

def signed_in?
  !current_user.nil?
end

def cannot_create_user
  respond_to do |format|
    format.html  { render :action => 'new' }
    format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
  end
end

n.b. Я не проверял это, это может не сработать, но вы должны понять ... если у вас есть модульные тесты (что, я надеюсь, вы делаете ...), вы сможете его уронить и посмотреть, работает ли он!

Следующим шагом будет использование accepts_nested_attribute_for для вашего объекта регистрации, чтобы его можно было отправлять как часть пользовательских параметров.

Я также реорганизовал бы это так, чтобы все настройки ролей и т. Д. Выполнялись в обратных вызовах .

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

Надеюсь, это поможет!

...