Создайте один объект и обновите другой в одном запросе

#ruby-on-rails

#ruby-on-rails

Вопрос:

В моем приложении Rails я хотел бы выполнить некоторые действия после входа пользователя в систему. Например:

  • Пользователь просматривает сайт. Он не вошел в систему.
  • Пользователь создает новый объект на сайте. Поскольку пользователь не вошел в систему, объект общедоступен.
  • Теперь пользователь хочет сделать объект приватным. Он нажимает кнопку «сделать приватным».
  • Поскольку он не авторизован, сайт не знает, с кем связать частный объект. Он перенаправляет его на форму входа.
  • Пользователь входит в свою учетную запись. Для входа в систему используется стандартный запрос RESTful POST. Затем — и это та часть, с которой мне нужна помощь — он также обновляет объект, чтобы сделать его закрытым. Затем он перенаправляет его обратно в (теперь частное) представление объекта.

Я новичок в Rails, но, насколько я понимаю, я не могу отправить запрос PUT с контроллера входа на другой контроллер объекта, поскольку перенаправления не позволяют отправлять данные.

Я полагаю, я мог бы также поместить некоторые переменные GET в путь входа (т. е. http://example.com/login?ref=123amp;action=make_private ), который контроллер входа в систему может интерпретировать как «сделать объект с идентификатором 123 приватным». Контроллер входа в систему может проверять наличие этих параметров всякий раз, когда создается новый логин, и обрабатывать обновление этого объекта самостоятельно. Но, похоже, должен быть лучший способ, чем копировать действие обновления из контроллера объекта в контроллер входа.

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

Я что-то упускаю из виду? Каков правильный способ сделать что-то подобное (если есть правильный способ)?

Ответ №1:

Я понимаю, о чем вы спрашиваете, поэтому я попробую пройти через это.

В момент, когда пользователь нажимает «сделать приватным», существует объект, который уже создан, правильно? Предполагая, что это так, просто передайте этот идентификатор объекта вместе с командой «сделать приватным», когда не вошедший в систему пользователь перенаправляется на страницу входа. Это означает, что у вас должен быть список параметров с чем-то вроде следующего: object_id => "1", method => "make_private"

Теперь у вас есть выбор, вы можете либо обновить объект в рамках метода проверки правильности входа, который у вас уже должен быть, выполнив это:

 if params[:object_id] amp;amp; params[:method] == "make_private"
  #make object private
  redirect_to objects_path(params[:object_id])
else 
  #normal login redirect
end
 

или вы можете перенаправить свой метод подтверждения входа в систему на метод обновления объекта и с их перенаправления на страницу просмотра объекта примерно следующим образом:

 def login_validation
  #normal login checking
  if params[:object_id] amp;amp; params[:method] == "make_private"
    redirect_to object_path(params[:object_id])
  else
    #redirect to normal after login page
  end
end
 

затем в вашем обновлении вы захотите:

 def update
  #normal update stuff   
  redirect_to objects_path(params[:object_id])
end  
 

Очевидно, вам понадобится что-то, что обнаружит команду «make private» в вашем методе обновления, но это не должно быть слишком сложно. Если вам нужна помощь в этом, просто прокомментируйте здесь, и я также добавлю инструкции для этого.

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

Например, ваша кнопка make private может выглядеть так

<%= button_to "Make Private", object_path(:id=>object_id) %>

Затем он попытается обновить, поймет, что у него нет зарегистрированного пользователя, и перенаправит на страницу входа в систему следующим образом:

 def update
  if user_logged_in?
    #do normal update stuff
  else
    redirect_to login_path(:redirect_path => object_path(params[:id])
end
 

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

<%= button_to "Confirm", login_validation_path(<normal login params>,params[:redirect_path]) %>

Затем внутри вашего login_validation вы выполните свои обычные проверки, а затем перенаправите на любой указанный вам путь.

 def login_validation
  #normal login stuffs
  if params[:redirect_path]
    redirect_to params[:redirect_path]
  else
    #normal redirect
end
 

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

Комментарии:

1. Спасибо. Чтобы уточнить, я понимаю, что для перехода к действию обновления вам нужно отправить запрос PUT, который, я не думал, что вы могли бы сделать через redirect_to . Я неправильно понимаю?

2. @user108338 Да. Вы можете использовать запросы PUT через redirect_to без проблем. Вам просто нужно убедиться, что все, что получает PUT, либо отображает, либо перенаправляет в другое место, к которому прикреплено действительное представление, поскольку в большинстве обновлений не будет прикрепленного файла ERB.

Ответ №2:

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

 def create
  @user = User.new user_params
  if @user.save
    @object = Object.find(params[:object_id])
    @object.update_attributes(:private => true)
  else
    render new
  end
end
 

Вы также можете использовать активные записи after_create callback

 class User < ActiveRecord::Base
  after_create :update_object

  def update_object
    #your logic to update object
  end
end
 

Обновить:

Если вы хотите обновить свой объект после входа пользователя в систему, вы можете сделать:

a. создайте свой маршрут для отправки запроса post , чтобы вы могли отправлять свой идентификатор объектов:

 post '/object/:id' => "your_controller#update_object", as: 'update_object'
 

б. Создайте свою ссылку для обновления этого объекта:

 <%= link_to "object", update_object_path(@object.id), method: :post %>
 

c. В вашем методе обновите свой объект:

 def update_object
  @object = Object.find(params[:id])
  @object.update_attributes(:private => true)
  redirect_to your_path, notice: "object made private"
end
 

Если вы используете devise для аутентификации, вы можете получить своего пользователя, current_user и если у вас есть своя пользовательская аутентификация, вы можете создать метод для поиска вашего текущего пользователя

  class ApplicationController < ActionController::Base
   def current_user
     @current_user ||= User.find(session[:user_id])
   end
 end
 

Комментарии:

1. Я не думаю, что создается пользователь.

2. @DickieBoy если вы посмотрите на его заголовок Create one object and update another in one request

3. @DickieBoy обновит мой ответ, чтобы обновить объект, как только пользователь войдет в систему.

4. Правильно, извините, создаваемый объект — это объект login (объект, представляющий сеанс пользователя, вошедшего в систему).

5. @user108338 обновил мой ответ, чтобы обновить ваш объект после входа пользователя в систему