Доступ к current_user в модели (или какой-либо другой обходной путь)

Я прочитал несколько ссылок SO по этой теме. Даже если вы можете взломать его, чтобы получить current_user в модели, вы не должны этого делать. Итак, каковы мои варианты в моем случае?

Я использую гем devise_invitable, и одна из команд — User.invite!({:email => email}, current_user), в которой хранится информация о том, кто пригласил пользователя (current_user). Я хотел бы иметь эту информацию.

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

# group.rb
  def user_emails
  end

  def user_emails=(emails_string)
    emails_string = emails_string.split(%r{,\s*})
    emails_string.each do |email|
      user = User.find_for_authentication(email: email)
      if user
        self.add user
        GroupMailer.welcome_email(user)
      else
        User.invite!(email: email) # But I want this: User.invite!({:email => email}, current_user)
        user = User.order('created_at ASC').last
        self.add user
      end
    end
  end

Если уместно, это просто text_area, которая получает эти электронные письма для обработки:

# groups/_form.html.erb
<%= f.text_area :user_emails, rows: 4, placeholder: 'Enter email addresses here, separated by comma', class: 'form-control' %>

Как мне запустить User.invite!({:email => email}, current_user) в этом процессе, не переделывая слишком много, чтобы эта полезная информация (кто кого пригласил) сохранялась в моей базе данных? Большое спасибо!


Обновление:

С помощью @Mohamad ниже у меня все заработало.

# group.rb
  def emails
  end

  def invite_many(emails, inviter)
    emails.split(%r{,\s*}).each do |email|
      if user = User.find_for_authentication(email: email)
        add user
        GroupMailer.group_invite user
      else
        add User.invite!({:email => email}, inviter)
      end    
    end
  end

# groups_controller.rb
  def update
    @group = Group.friendly.find(params[:id])
    if @group.update_attributes(group_params)
      emails = params[:group][:emails]
      @group.invite_many(emails, current_user) # also put this in #create
      redirect_to @group
    else
      flash[:error] = "Error saving group. Please try again."
      render :edit
    end
  end

И затем ничего в моей модели пользователя, потому что User.invite уже определен devise_invitable, и мне больше ничего не нужно было делать. Этот процесс работает отлично сейчас!


person iamse7en    schedule 13.09.2015    source источник
comment
Как определяется invite!? Как сохранить приглашенного пользователя? Если вы сделаете что-то вроде User.invite!(email: email, invited_by: current_user), вы не получите доступ к current_user в модели: модель не знает, что invited_by установлено в current_user, знает только контроллер.   -  person eirikir    schedule 13.09.2015
comment
devise_invitable позаботится обо всем этом. Я знаю, что не могу запустить User.invite!(email: email, invited_by: current_user) в модели, потому что он не знает current_user. Мне просто интересно, какой обходной путь я мог бы сделать, чтобы devise_invitable знал, кто отправил приглашение.   -  person iamse7en    schedule 13.09.2015


Ответы (3)


Есть некоторые тонкие проблемы с вашим кодом. В ветке else вашего кода существует потенциальное состояние гонки, где вы пытаетесь добавить последнего созданного пользователя. Я также не уверен, что вам нужен метод установки здесь, если вы не получаете доступ к emails из другого места в экземпляре Group.

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

Я бы сделал что-то вроде этого:

def invite_many(emails, inviter)
  emails.split(%r{,\s*}).each do |email|
    if user = User.find_for_authentication(email: email)
      add user
      GroupMailer.welcome_email user
    else
      add User.invite!(email, inviter)
    end    
  end
end

# controller
@group.invite_many(emails, current_user)

# User.invite
def invite(email, inviter)
  # create and return the user here, and what else is necessary
end
person Mohamad    schedule 13.09.2015
comment
благодарю вас. Я сейчас пробую этот подход. Я изменил свой :text_area на :emails, чтобы быть последовательным, и я поместил @group.invite_many(emails, current_user) в контроллер как при создании, так и при обновлении (поскольку пользователь может пригласить больше пользователей, просто отредактировав группу и отправив форму) сразу после if @group.save... Один раз он дошел до этой строки, он не знал, что такое «электронные письма», поэтому я изменил это на params[:emails], затем он переходит к методу приглашения_many в модели, но не знал, что такое emails, так что это было . разделить на нилькласс. Я делаю все это неправильно? Спасибо за ваше руководство. - person iamse7en; 19.09.2015
comment
Ничего себе, я разобрался! и обновил то, что я сделал выше. Еще раз спасибо, это гораздо более чистый процесс. - person iamse7en; 19.09.2015

Если вы вызываете user_emails() из контроллера (и я предполагаю, что вы должны быть там, где вы получаете форму для передачи в emails_string), вы можете передать current_user:

user_emails(emails_string, current_user)

и измените user_emails, чтобы получить его:

def user_emails=(emails_string, current_user)

person Joseph    schedule 13.09.2015

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

person rakeshpatra    schedule 13.09.2015
comment
никогда не заходите в сессию внутри модели! - person Tim Kretschmer; 13.09.2015