nourza
nourza

Reputation: 2321

can't write unknown attribute `user_id`

I am using gem devise for creating user profiles. Every user can create comments in any profile I want to add each user name under the comment he wrote.

A user has many comments

A user has many profile comments, this is the relationship between a user and the comments This is the error that I got when I create a comment

can't write unknown attribute `user_id`

Here is what I did

class CreateProfileComments < ActiveRecord::Migration
      def change
        create_table :profile_comments do |t|
    
          t.timestamps null: false
        end
      end
    end

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :text
      t.references :user, index: true, foreign_key: true
      
      t.timestamps null: false
    end
  end
end

in user.rb model

  has_many :comments
  has_many :profile_comments, dependent: :destroy

in comment.rb

class Comment < ActiveRecord::Base
  belongs_to :user #not users as you have defined in your question
  has_many :profile_comments
end

in profile comment.rb

class ProfileComment < ActiveRecord::Base
  belongs_to :comment
  belongs_to :user
end

in comment controller

class CommentsController < ApplicationController
  before_action :find_comment ,only:[:show,:update,:edit,:destroy]

   def new
    @user =User.find(params[:id])
    @comment = @user.comments.build
  end

  def index

  end

  def create
    @user =User.find(params[:id])
    @comment = current_user.comments.build(comment_params)
    @profile_comment = ProfileComment.new
    @user.profile_comments < @profile_comment
    @comment.profile_comment < @profile_comment
    if @comment.save
      redirect_to doctor_path(:id => @user.id)
    end
  end 

  def edit
  end

  def update

    if @comment.update(comment_params)
      redirect_to root_path, alert: "user Information updated successfully"
    else
      flash.now[:error] = "Couldn't update!"
      render :edit
    end
  end
  def destroy
    @comment.destroy
    redirect_to doctors_path, notice: "comment deleted Successfully"
  end 

private

  def find_comment
    @comment = Comment.find(params[:id])
  end

  def comment_params
    params.require(:comment).permit(:text)
  end
end

in user profile view

      <% @user.profile_comments.each do | profile_comment |%>
  <%comment = profile_comment.comment%>
  <% if comment.text.present? %>
    <%= comment.text %><br>
    <%if comment.user.blank?%>
      No user assigned to this comment
    <%else%>
      <%= comment.user.name #or email or whatever%>
    <%end%>
    <br><hr>
  <% end %>
<% end %>

Upvotes: 0

Views: 1412

Answers (1)

max
max

Reputation: 102055

I'm guessing what you actually want is just to create two assocations pointing to the same table:

class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :text
      t.references :user, index: true, foreign_key: true
      t.references :author, index: true, foreign_key: { to_table: :users }
      t.timestamps null: false
    end
  end
end

Here user_id references the target user of the comment and author_id references the user writing the comment. Both reference users.id.

Then create two belongs_to associations in your comment model:

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :author, 
    class_name: 'User', 
    inverse_of: :authored_comments
end

And two has_many associations in your User model:

class User < ApplicationRecord
  # comments about this user
  has_many :comments 
  # comments written by this user 
  has_many :authored_comments, 
    class_name: 'Comment',
    foreign_key: :author_id,
    inverse_of: :author
end

I have no idea why you would want to mix in another table as both relations are one to many.

class CommentsController < ApplicationController
  before_action :set_user, only: [:new, :create]
  
  # ...

  def new
    @comment = @user.comments.new
  end

  def create
    @comment = @user.comments.new(comment_params) do |c|
      c.author = current_user
    end
    if @comment.save
      redirect_to doctor_path(id: @user.id)
    else
      render :new
    end
  end 

  private

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

  # ...
end

If you then want to display comments you would do:

<% @user.comments.each do |comment| %>
<div class="comment">
  <div class="body">
    <%= comment.body %>
  </div>
  <p class="author"><%= comment.author.email %></p>
</div>  
<% end %>

Upvotes: 1

Related Questions