Используя devise в рельсах, пытаясь добавить второй шаг после регистрации, чтобы обновить пользователя с именем, биографией и фотографией - PullRequest
1 голос
/ 28 марта 2020

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

1 / Новые данные не учитываются 2 / Перенаправление неверно

После входа в систему пользователь перенаправлен на " профили /: идентификатор / редактирование». После отправки формы, он перенаправляет на «user /: id», который не существует.

Разве он не должен перенаправлять на # обновление профиля в контроллере?

Вот мои разные коды:

1 / маршруты

Rails.application.routes.draw do
  devise_for :users
  root to: "pages#home"
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :jam_sessions, only: [:show, :index, :new, :create] do
    resources :spots, only: [:show, :create, :new]
    resources :messages, only: [:create]
  end
  resources :participations, only: [:create, :update]

  resources :profiles, only: [:show, :edit, :update]
  resources :dashboards, only: [:index, :show]


  resources :reviews, only: [:create]


  mount ActionCable.server => "/cable"

  get 'users/:id', :to => 'profiles#edit', :as => :user

  patch 'profiles#edit', :to => 'profiles#update'
end 

2 / profile_controller

class ProfilesController < ApplicationController
  def show

    @user = User.find(params[:id])
    @reviews = Review.where(receiver_id: @user.id)
    @instruments = UserInstrument.where(user_id: @user.id)
    @participations = Participation.where(user_id: @user.id)
    date = Time.now

    if @participations != nil
      @jam_sessions = []

      @participations. each do |participation|
        spot = Spot.find_by(id: participation.spot_id)
        @jam_sessions << JamSession.find_by(id: spot.jam_session_id)

      end
      @future_jam_sessions = []
      @past_jam_sessions = []
      @jam_sessions.each do |jam_session|
        if jam_session.starts_at > date
          @future_jam_sessions << jam_session
        else
          @past_jam_sessions << jam_session
        end
      end
    else
      puts "no jam"
    end
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    @user.update(user_params)
    raise
    if @user.save
      redirect_to profiles_path(@user)
    else
      render "new"
    end
  end
  private

    def user_params
      params.require(:user).permit(:first_name, :last_name, :bio)
    end
end

3 / application_controller

class ApplicationController < ActionController::Base
  before_action :authenticate_user!, except: [:home, :index, :show]

  before_action :configure_permitted_parameters, if: :devise_controller?
  def configure_permitted_parameters
    # For additional fields in app/views/devise/registrations/new.html.erb
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :bio])
    # For additional in app/views/devise/registrations/edit.html.erb
    devise_parameter_sanitizer.permit(:account_update, keys: [:username])
  end

  def default_url_options
    { host: ENV["DOMAIN"] || "localhost:3000" }
  end

end

4 / модель пользователя

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :user_instruments, dependent: :destroy
  has_many :instruments, through: :user_instruments
  has_many :messages, dependent: :destroy
  has_one_attached :photo, dependent: :destroy
  has_many :reviews_written, class_name: "Review", foreign_key: :writer_id
  has_many :reviews_received, class_name: "Review", foreign_key: :receiver_id
  has_many :jam_sessions, dependent: :destroy

  def profile_picture
    if photo.attached?
      photo.key
    else
      "avatar-unknown.png"
    end
  end

  def full_name
    "#{first_name} #{last_name}"
  end
end

5 / вид редактирования

<%= simple_form_for(@user) do |f| %>
  <%= f.input :first_name %>
  <%= f.input :last_name %>
  <%= f.input :bio %>
  <%= f.input :photo, as: :file %>
    <%= f.submit 'Update profile' %>
<% end %>

Спасибо! Оливье

1 Ответ

2 голосов
/ 29 марта 2020

это Клара здесь :)

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

В вашем контроллере приложений есть эта строка, которая не нужна: devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :bio]) Вы бы только необходимо разрешить дополнительные параметры для формы устройства, если вы добавите их непосредственно в форму регистрации устройства. Но здесь вы добавляете новую форму.

Итак, как мы можем обработать новую форму? Проблема в вашем коде очень тонкая. Вы изменяете пользовательский объект, но вы решили использовать profiles controller, включая профили маршрутов (но у вас также есть несколько пользовательских маршрутов). Дело в том, что в форме редактирования пользователя следующая строка определяет, куда будут отправляться HTTP-запросы, как только кто-то нажмет кнопку «Отправить».

<%= simple_form_for(@user) do |f| %>

Откройте браузер и посмотрите в режиме проверки, который генерируется html, это будет что-то вроде этого (у него будет больше вещей, но это интересная часть для нас)

<form action="/users" accept-charset="UTF-8" method="patch">

Это означает, что когда кто-то нажимает submit, запрос HTTP PATCH делается на /users Сейчас то, как ваши маршруты строятся в настоящее время, они не приспособлены для этого.

Таким образом, вы можете добавить новые маршруты

resources :users, only [:update]

В users_controller#update вы можете поместить код у вас сейчас profiles_controller#update.

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

  1. Переместить все на пользовательский контроллер. Таким образом, вы можете редактировать и обновлять маршруты для контроллера пользователя, редактировать и обновлять действия (такие же, как profile_controller # edit и #update в вашем коде) и представление. Не забудьте удалить материал в профилях, или через две недели это будет очень запутанно).
  2. Скажите простую форму, не go на users_controller, а profiles_controller, и вы можете сохранить настройку, как у вас есть. Вы можете сделать это, добавив эту строку
 simple_form_for :user, url: user_path, method: "PATCH" ```

Еще несколько замечаний:

В routes.rb последняя строка неверна. И вместо того, чтобы определять обычные действия CRUD вручную, вы должны использовать этот синтаксис:

...
resources :users, only: [:edit, :update]
...

И в profiles controller в действии update, и там вам нужно изменить рендер. (Неважно, если вы оставите его там или переместите его в users_controller). Это должно быть:

 if @user.save
   redirect_to profiles_path(@user)
 else
   render "edit"
 end

Когда пользователь не будет сохранен, вы хотите отобразить edit, а не new.

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

Если вы хотите провести проверку, скажем, :bio, она не будет работать с этой настройкой, которая у вас есть сейчас, потому что Пользовательский объект уже был создан при отправке формы регистрации устройства. И на этом первом этапе проверки будут проверены - так что вы не сможете проверить, была ли биография уже там или нет. Есть драгоценные камни, чтобы справиться с этим, и я также нашел эту статью для дальнейшего исследования. https://www.honeybadger.io/blog/multi-step-forms-in-rails/

...