Предотвратить прямое выполнение действия контроллера пользователем в Rails

У меня возникла ситуация, когда мне нужно запретить пользователям явно вызывать say /town/addBuilding. Город — это мой контроллер, а addBuilding — выполняемое действие.

Теперь дело в том, что это действие должно выполняться только в коде моей программы, а не пользователем, запрашивающим его выполнение. Более того, это действие выполняется как обратный вызов. В моем application_controller при выполнении некоторого условия срабатывает действие контроллера и происходит перенаправление. В php будет достаточно простой защиты, такой как определение защиты и проверка на нее. Есть ли что-то подобное в рельсах, и если да, то как лучше всего это реализовать?

Спасибо за чтение, и я ценю вашу помощь :)

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

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

def checkQuest
if TavernQuest.hasQuest(current_user)
  quest = TavernQuest.getQuest(current_user)
  if quest.end_time < Time.now # get quest info and check if the quest has been completed
    TavernQuest.deleteQuest(current_user)
    redirect_to :controller => 'tavern', :action => 'monsterAttack'
  end
end
end

Действие контроллера таверны — это просто код, который я хочу выполнить, но только если перенаправление происходит внутри контроллера приложения.


person Spyros    schedule 24.11.2010    source источник


Ответы (2)


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

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

Пример реализации:

class TavernQuest

  def self.user_quest_is_expired?(user)
    quest = getQuest(current_user)
    if quest && quest.end_time < Time.now 
      TavernQuest.deleteQuest(current_user)
      true
    else
      false
    end
  end
end

и в вашем контроллере вам просто нужно написать

redirect_to :controller => 'tavern', :action => 'monsterAttack' if TavernQuest.user_quest_is_expired?(current_user)
person nathanvda    schedule 24.11.2010
comment
Это мало помогает. Как бы вы предложили это сделать? Для меня это точно похоже на код контроллера. - person Spyros; 25.11.2010
comment
Здравствуйте, извините за поздний ответ, я пропустил ваше редактирование. Ваша реализация действительно понятнее, но она не решает проблему явного вызова. Пользователь по-прежнему сможет выполнить tavern/monsterAttack. Я хочу предотвратить это и называть это только своим перенаправлением. - person Spyros; 29.11.2010
comment
Кажется, я могу сделать это, включив в код еще немного логики, мне придется это уточнить. Спасибо ;) - person Spyros; 29.11.2010
comment
Что происходит, когда у вас вообще нет «current_user» (анонимный пользователь) без квеста, но вы полностью хотите, чтобы пользователь получил доступ с другого контроллера. - person muhammadn; 15.08.2014

Поместите метод addBuilding под строку, начинающуюся с protected, следующим образом:

protected
def addBuilding
   #your code
end

Наслаждаться!

EDIT: В дополнение к этому вы также можете использовать before_filter в своих контроллерах... Я скоро опубликую точный синтаксис.

 before_filter :addBuilding, :only => :method_name

имя_метода — это метод, из которого можно получить доступ к :addBuilding, никакой другой метод не может получить доступ к этому методу после добавления в этой строке.

РЕДАКТИРОВАТЬ: Хорошо, исходя из предоставленной вами информации, protected не будет работать, поскольку, если мы поместим ваше секретное действие под protected, только tavern контроллер будет иметь к нему доступ.

EDIT: рассмотрите возможность использования сеансов, чтобы проверить, есть ли у пользователей действительный сеанс, когда они пытаются выполнить действие monsterAttack.

person Jasdeep Singh    schedule 24.11.2010
comment
Привет, Джасдип, и спасибо за очень быстрый ответ. Проблема в том, что я перенаправляю на addbuilding, например redirect_to :controller =› 'town', :action =› 'addbuilding через мой application_controller (через обратный вызов, как я упоминал в первом посте), и поэтому private,protected не работают. Before_filter может работать, но будет ли работать перенаправление внутри модели (через имя_метода, я имею в виду, так как в конечном итоге мне придется вызывать addbuilding). посмотрю, спс:) - person Spyros; 24.11.2010
comment
нет проблем, Спирос, найдите время, чтобы пометить этот ответ как принятый, если он сработал для вас .. :) - person Jasdeep Singh; 24.11.2010
comment
зачем вам перенаправлять с application_controller ?? Что заставляет вас перенаправлять на это действие из application_controller? Кроме того, before_filter должен работать нормально, просто поместите действие, которое перенаправляет, после тега :only - person Jasdeep Singh; 24.11.2010
comment
Мне нужно использовать application_controller, потому что это обратный вызов. Он основан на времени, поэтому через 2 минуты его следует вызывать перед любым другим действием контроллера. Я попробую before_filter сейчас и дам вам знать, спасибо за быстрые ответы :) - person Spyros; 24.11.2010
comment
Конечно, попробуйте хелпер before_filter и посмотрите, работает ли он. Можете ли вы опубликовать свой application_controller, чтобы сообщество могло его посмотреть и проанализировать? - person Jasdeep Singh; 24.11.2010
comment
хм, я могу ошибаться, но я думаю, что before_filter в этом случае не сработает, потому что before_filter должен быть частью контроллера города, а перенаправление происходит на контроллере приложения. Я вставлю немного кода, как вы предложили, так будет лучше, я сейчас редактирую основной пост. - person Spyros; 24.11.2010
comment
Я думал об использовании сеанса или какой-либо другой ситуации блокировки (например, значения базы данных), но я немного боюсь условий гонки и других возможных предостережений). Однако, если нет другого пути, я думаю, мне придется сделать это так, спасибо :) - person Spyros; 24.11.2010
comment
Я бы посоветовал вам использовать сеансы вместо блокировок базы данных, поскольку сеансы было бы проще реализовать. - person Jasdeep Singh; 24.11.2010