简体   繁体   中英

Joining two models with Rails

I currently have a Subscriber model and a Comment model. The Subscriber has_many comments and the comment belongs_to Subscriber . All I want is for a Subscriber to be able to make a comment in a text field and that comment belongs to that Subscriber through an id. For some reason I can't not figure this out and I'm having a tough time getting help. So, to be very clear I have a subscriber_id on the comment model, how do I attach them together so that I can make this call in the Rails Console - @comment = @subscriber.comments.first and see the first comment that belongs to that particular subscriber? I'll show some code for clarity.

SCHEMA:

         create_table "comments", force: :cascade do |t|
t.string   "description"
t.datetime "created_at",    null: false
t.datetime "updated_at",    null: false
t.string   "fav_drink"
t.string   "visit_time"
t.integer  "subscriber_id"
end

create_table "subscribers", force: :cascade do |t|
t.string   "first_name"
t.string   "last_name"
t.string   "email"
t.string   "phone_number"
t.string   "birthdate"
t.string   "street_1"
t.string   "street_2"
t.string   "city"
t.string   "zip"
t.string   "state"
t.datetime "created_at",   null: false
t.datetime "updated_at",   null: false
t.integer  "visit"
end

CONTROLLERS:

class CommentsController < ApplicationController
def new
  @comment = Comment.new
end

def create
  @comment = Comment.create(comments_params)
  if @comment.save
    flash[:notice] = "Thank you!"
    redirect_to subscribers_search_path(:comments)
  else
    render "new"
  end
end

private

def comments_params
  params.require(:comment).permit(:fav_drink, :subscriber_id)
end
end



class SubscribersController < ApplicationController
 def index
  @subscriber = Subscriber.all
 end

 def new
  @subscriber = Subscriber.new
end

def create
  @subscriber = Subscriber.create(subscriber_params)
  if @subscriber.save
    flash[:notice] = "Subscriber Has Been Successfully Created"
    redirect_to new_subscriber_path(:subscriber)
  else
    render "new"
  end
end

And the Models are as described in the intro. Thank You!

There are several ways of going about this. I'd highlight 3 below:

  1. Use a nested resource routes, for example:

    resources :subscribers do resources :comments end

Using this approach your routes would become subscribers/1/comments... and in your comments_controller, you can fetch your subscriber from params[:subscriber_id]

  1. If the subscriber is the current_user, you could as well set it in your comments_controller as such:

    current_user.comments.create(comments_params)

  2. Use a hidden field in your comments/form to set the subscriber.

Basically, looking at your comments_params , you're requiring the subscriber_id , which is not being passed to the controller. So you need a way of passing this down.

You could set your subscriber before the create/new action and then do:

@subscriber.comments.[create|new] then in your new comments form view, you would have f.hidden_field :subscriber_id

Let me know if that works.

There are multiple approaches:

Approach 1: Using current_user/ logged_in user

If the subscriber is supposedly logged into the system, and if the current_user is the reference to the logged_in subscriber, then you could assign the current_user to the comment before creating.

class CommentsController < ApplicationController
  def new
    @comment = Comment.new
  end

  def create
    @comment = current_user.comments.build(comments_params)

    if @comment.save
      flash[:notice] = "Thank you!"
      redirect_to subscribers_search_path(:comments)
    else
      render "new"
    end
  end

  private

  def comments_params
    params.require(:comment).permit(:fav_drink)
  end
end

Approach 2: Hidden Field

Set a subscriber_id hidden_field in the comments form and then your existing implementation should work fine. Just for clarify I am copy/pasting your implementation.

class CommentsController < ApplicationController
  def new
    @comment = Comment.new
  end

  def create
    @comment = Comment.new(comments_params)

    if @comment.save
      flash[:notice] = "Thank you!"
      redirect_to subscribers_search_path(:comments)
    else
      render "new"
    end
  end

  private

  def comments_params
    params.require(:comment).permit(:fav_drink, :subscriber_id)
  end
end

Approach 3: Nested Resource

Using the rails nested resource, set your routes to the following:

resources :subscribers
  resources: comments, only: [:new, :create]
end

Then update your controller code to the following:

class CommentsController < ApplicationController
  def new
    @comment = Comment.new
  end

  def create
    @subscriber = Subscriber.find(params[:subscriber_id])
    @comment = @subscriber.comments.build(comments_params)

    if @comment.save
      flash[:notice] = "Thank you!"
      redirect_to subscribers_search_path(:comments)
    else
      render "new"
    end
  end

  private

  def comments_params
    params.require(:comment).permit(:fav_drink)
  end
end  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM