@Tarzan3154

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Rails 自己紹介ページに写真投稿&いいね機能

解決したいこと

Railsで自己紹介ページに写真投稿&いいねができる機能を付け、共有できるサービスを作成しておりました。ユーザ詳細ページの一部分にSKILL(自分の得意としていることや勉強していることを入力するスペース。titleとdescriptionを用意)部分を設け、ユーザ詳細変更画面で編集できるようにしていたのですが、show.html.erbにてskill部分を実装後、下記のエラー画面が表示されるようになったのですが、原因をご教示お願いできないでしょうか?

①ユーザ詳細画面で、ActiveRecord::StatementInvalid in UsersController#showが表示される。

発生している問題・エラー

ActiveRecord::StatementInvalid in UsersController#show
Mysql2::Error: Unknown column 'users.user_id' in 'where clause': SELECT `users`.* FROM `users` WHERE `users`.`user_id` = 1 LIMIT 1
  def show
    @user = User.find(params[:id])
    @skill = @user.skills.page(params[:page])
  end

  def new

該当するソースコード

routes.rb

Rails.application.routes.draw do
  root to: 'toppages#index'

  get 'login', to: 'sessions#new'
  post 'login', to: 'sessions#create'
  delete 'logout', to: 'sessions#destroy'

  get 'signup', to: 'users#new'
  resources :users, only: [:index, :show, :new, :create, :edit] 

  put 'users/:id/edit', to: 'users#edit'

  put '/users/:id', to: 'users#update'
  get 'users/:id/edit', to: 'users#edit'

  resources :posts
  resources :skills, only: [:create, :edit, :destroy]
end
users_controller.rb

class UsersController < ApplicationController
  before_action :require_user_logged_in, only: [:index, :show]
  before_action :correct_user, only: [:edit]

  def index
    @users = User.order(id: :desc).page(params[:page]).per(50)
  end

  def show
    @user = User.find(params[:id])
    @skill = @user.skills.page(params[:page])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)

    if @user.save
      flash[:success] = 'ユーザを登録しました。'
      redirect_to @user
    else
      flash.now[:danger] = 'ユーザの登録に失敗しました。'
      render :new
    end
  end

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

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

    if @user.update(user_params)
      flash[:success] = 'プロフィールを変更しました。'
      redirect_to @user
    else
      flash.now[:danger] = 'プロフィールが変更できませんでした。'
      render :edit
    end
  end

  private

  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation, :profession, :first_name, :last_name, :profile,)
  end

  def correct_user
  end
end
skills_controller.rb

class SkillsController < ApplicationController
  before_action :require_user_logged_in
  before_action :correct_user, only: [:destroy]

  def create
    @skills = current_user.skills.build(skill_params)
    if @skill.save
      flash[:success] = "スキルを登録しました。"
      redirect_to root_url
    else
      @skills = current_user.feed_skills.order(id: :desc).page(params[:page])
      flash.now[:danger] = "スキルの登録に失敗しました。"
      render "users/edit"
    end
  end

  def edit
  end

  def destroy
    @skill.destroy
    flash[:success] = "スキルを削除しました。"
    redirect_back(fallback_location: root_path)
  end
end
users/show.html.erb

<div class="row">
  <aside class="col-sm-12">
    <div class="text-left">
      <%= link_to 'プロフィール変更', edit_user_path(@user) %>
    </div>
  </aside>

  <aside class="col-sm-12">
    <table class="table table-bordered">
      <tr>
        <th>職業</th>
        <td><%= @user.profession %></td>
      </tr>
      <tr>
        <th>名前</th>
        <td><%= @user.last_name %> <%= @user.first_name %></td>
      </tr>
      <tr>
        <th>自己紹介</th>
        <td><%= @user.profile %></td>
      </tr>
    </table>
  </aside>

  <aside class="col-sm-12">
    <div class="center jumbotron">
      <div class="text-center">
        <h2>SKILL</h2>
      </div>
    </div>
  </aside>
  <aside class="col-sm-6">
    <div class="center jumbotron">
      <div class="text-center">
        <img class="rounded img-fluid" src="<%= gravatar_url(@user, { size: 250 }) %>" alt="">
      </div>
    </div>
  </aside>
  <aside class="col-sm-6">
    <div class="center jumbotron">
      <div class="text-center">
        <%= @skill.title %>
      </div>
    </div>
    <div class="center jumbotron">
      <div class="text-center">
        <%= @skill.description %>
      </div>
    </div>
  </aside>
</div>
users/edit.html.erb

<div class="text-center">
  <h1>プロフィール変更画面</h1>
</div>

<div class="row">
  <div class="col-sm-6 offset-sm-3">

    <%= form_with(model: @user, local: true, method: :put) do |f| %>
      <%= render 'layouts/error_messages', model: f.object %>

      <div class="form-group">
        <%= f.label :profession, 'Profession' %>
        <%= f.text_field :profession, class: 'form-control' %>
      </div>

      <div class="form-group">
        <%= f.label :first_name, 'First Name' %>
        <%= f.text_field :first_name, class: 'form-control' %>
      </div>

      <div class="form-group">
        <%= f.label :last_name, 'Last Name' %>
        <%= f.text_field :last_name, class: 'form-control' %>
      </div>

      <div class="form-group">
        <%= f.label :profile, 'Profile' %>
        <%= f.text_field :profile, class: 'form-control' %>
      </div>

  <div class="text-left">
    <h3>Security</h3>
  </div>

      <div class="form-group">
        <%= f.label :email, 'Email' %>
        <%= f.email_field :email, class: 'form-control' %>
      </div>
      <div class="form-group">
        <%= f.label :password, 'Password' %>
        <%= f.password_field :password, class: 'form-control' %>
      </div>

      <%= f.submit '更新', class: 'btn btn-primary btn-block' %>

  <div class="text-left">
    <h3>SKILL</h3>
  </div>

      <%= render 'skills/edit', skills: @skill %>
    <% end %>
  </div>
</div>
skills/_edit.html.erb

<%= form_with(model: @user, local: true, method: :put) do |f| %>
  <%= render 'layouts/error_messages', model: f.object %>

  <div class="form-group">
    <%= f.label :title, 'Skill Title' %>
    <%= f.text_field :title, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :description, 'Skill Descriotion' %>
    <%= f.text_field :description, class: 'form-control' %>
  </div>

  <%= f.submit '更新', class: 'btn btn-primary btn-block' %>
<% end %>
user.rb

class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                  format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                  uniqueness: { case_sensitive: false }
  validates :password, allow_blank: true, length: { maximum: 20 }
  validates :profession, allow_blank: true, length: { maximum: 20 }
  validates :first_name, allow_blank: true, length: { maximum: 10 }
  validates :last_name, allow_blank: true, length: { maximum: 10 }
  validates :profile, allow_blank: true, length: { maximum: 200 }
  has_secure_password

  has_many :posts
  has_one :skills, class_name:"User"
end
skill.rb

class Skill < ApplicationRecord
  has_one :user

  validates :title, length: { maximum: 10 }
  validates :description, length: { maximum: 150 }
end

自分で試したこと

users#showにて@skillを定義後、現在のエラーが表示されるようになり、いま出ているMysql2::Error: Unknown column のエラーはUserとSkillのリレーションがうまくいっていなそうなのでまた別問題が起きていそうかと思いましたが、ルーティングの記述やモデルファイルの記述で修正点はありますでしょうか?

0 likes

多分models/user.rbskillsの設定がおかしいのかなと。
UserとSkillは1対多の関係ですよね?(1ユーザーが複数のskillを持つ)

それなら

user.rb
class User < ApplicationRecord
...
...

  has_many :skills # skill側に t.references :user とあると思ってる
end
skill.rb
class Skill < ApplicationRecord
  belongs_to :user

...
...
end

という一般的な設定で良いのかと。

has_oneを使うケースはよくよく考えないと... 案外使うケースは少ない。

0Like

@github0013@github
ご回答ありがとうございます。
ご指摘の点、修正してみましたが、
「NoMethodError in Users#show」が表示されるようになってしまいました。

NoMethodError in Users#show
undefined method `title' for #<ActiveRecord::AssociationRelation []>
    <div class="center jumbotron">
      <div class="text-center">
        <%= @skill.title %>
      </div>
    </div>
    <div class="center jumbotron">

ご指摘の点は正しいとは思いますが、現時点では原因は???です。
マイグレーションファイルも載せておきますが、何か修正点はありますでしょうか?

20201026001900_create_skills

class CreateSkills < ActiveRecord::Migration[5.2]
  def change
    create_table :skills do |t|
      t.string :title
      t.text :description
      t.references :user, foreign_key: true

      t.timestamps
    end
  end
end
0Like

変数名なんで、なんでも良いって言えば良いんですが、単数形の中身が配列っていうのも気持ち悪いのでこういう風に変えたほうが良いと思います。

users_controller.rb
class UsersController < ApplicationController
...
...

  def show
    @user = User.find(params[:id])
-    # @skill = @user.skills.page(params[:page])
+    @skills = @user.skills.page(params[:page])
  end

そしてundefined method 'title' for #<ActiveRecord::AssociationRelation []> が出るのは配列(正確には配列ではなくてActiveRecord::AssociationRelationだけど、配列のように操作できるのでここでは配列と言っておきます)にtitleっていうメソッドがないよっていうエラーなので、これはこの通りです。

1userに複数のskillが想定されるのなら、.eachとかで回すのが普通と思います。

<% @skills.each do |skill| %>

...
...

<% end %>

あと、いきなりrails全体で動かしてデバックするよりはコンソールを使ったほうが良いと思いますよ。

$ rails c 

> 
1Like

Your answer might help someone💌