Рефакторинг логики представления в Rails - PullRequest
1 голос
/ 23 ноября 2011

Вот что мне нужно сделать. У меня есть модель Tournament, которая подключена к User через Signup (N: N).

Единственное, что добавляет Signup, это статус регистрации. Турнир имеет время начала, и пользователи могут зарегистрироваться только за 60 минут до начала турнира. После этого зарегистрированные пользователи могут зарегистрироваться. Поэтому в основном у меня есть два варианта состояния

Короче, модели выглядят так:

class Signup < ActiveRecord::Base
  REGISTERED = 0
  CHECKED = 1

  belongs_to :tournament
  belongs_to :user
end

class Tournament < ActiveRecord::Base
  has_many :signups
  has_many :users, :through => :signups
end

class User < ActiveRecord::Base  
  has_many :signups
  has_many :tournaments, :through => :signups
end

Я пропустил некоторый код, чтобы сохранить это коротким. Проблема с представлением, так как у меня есть много условий, чтобы иметь в виду. Вот мой реальный код ( с использованием Slim в качестве движка шаблонов )

- if logged_in?
  - if current_user.registered_for?(@tournament)
    - if @tournament.starts_at < 60.minutes.from_now
      p Signups are closed, only registered users can now check in
      - if current_user.registered_for?(@tournament)
        = button_to "Checkin!", { :controller => :signups, :action => :update, :id => @tournament.id }, :method => :put
    - else
      = button_to "Cancel your registration for the tournament", { :controller => :signups, :action => :destroy, :id => @tournament.id }, :method => :delete
  - elsif current_user.checked_in?(@tournament)
    p You have already checked in.            
  - elsif @tournament.starts_at > 60.minutes.from_now
    = button_to "Sign up for the tournament", :controller => :signups, :action => :create, :method => :post, :id => @tournament.id
  - else
    p
      | The tournament starts in less than 60 minutes, you can't sign in
- else
  p 
    | You need to 
    |  
    = link_to "log in", login_path
    |  to play

Проблема в том, что я понятия не имею, как сделать это намного чище. Я имею в виду, да, я могу добавить помощников для кнопок, но это не поможет мне с уродством if if else else, потому что есть много разных комбинаций. Вот краткий список:

  • пользователь не авторизован
  • до начала турнира более 60 лет, и пользователь еще не зарегистрировался для участия в турнире
  • до начала турнира более 60 лет, и пользователь уже зарегистрирован
  • до 60 минут, но пользователь еще не зарегистрирован
  • прошло менее 60 минут, и пользователь зарегистрирован, но не зарегистрировался
  • прошло менее 60 минут, а пользователь уже зарегистрировался

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

Основная проблема в том, как мне обращаться с такими случаями? Просто кажется таким ужасным делать это в представлении, но я не вижу другого более простого способа.

Ответы [ 2 ]

5 голосов
/ 24 ноября 2011

Более чистым способом было бы создать осмысленные методы на ваших моделях.Например, в вашей модели Турнира добавьте что-то вроде:

def can_register?( user )
  !user.registered_for?(self) && self.starts_at > 60.minutes.from_now
end

И затем, на ваш взгляд, вы можете проверить на can_register? перед тем, как что-то отобразить.Добавление логики в представление, как вы сделали, - это не то, что предназначено для приложения MVC.

2 голосов
/ 24 ноября 2011

Вы должны использовать объект для инкапсуляции логики.Может быть, что-то вроде этого:

class UserSignup

  def initialize(user, tournament)
    @user, @tournament = user, tournament
  end

  def registered?
    @user.registered_for?(@tournament)
  end

  def signups_closed?
    @tournament.start_at < 1.hour.from_now
  end

  def checked_in?
    @user.checked_in?(@tournament)
  end

end

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

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

class SignupPresenter

  def initialize(user_signup)
    @user_signup = user_signup
  end

  def register_button
    view.button_to("sign up") if @user_signup.registered?
  end

  # etc ...

end

Кроме того, я хотел бы рассмотреть возможность использования различных шаблонов или даже контроллеров для разных пользователей.Так что пользователи, которые вообще не вошли в систему, не могут даже получить доступ к этой странице, и у администраторов есть другой контроллер (даже пространство имен) вместе.

Я бы не стал просто входить и разбивать его на частичные, потому чтопросто скрыть логику.Мне также нравится отдельный объект больше, чем помещать его в модель, потому что таким образом модель не будет сильно загромождена, и вся логика останется вместе, хорошо сфокусированной.

...