Reputation: 39
I'm trying to do user reviews, when user can write review to another user, i create tables review with :content, user_reviews with :for_user_id, and by_user_id, my routes
devise_for :users
resources :users, :only => [:show] do
resources :reviews
end
class Review < ActiveRecord::Base
belongs_to :user
has_many :users, :through => :users_reviews
end
class User < ActiveRecord::Base
has_many :users_review
has_many :reviews, :through => :users_review
end
class UsersReview < ActiveRecord::Base
belongs_to :user
belongs_to :review
end
class ReviewsController < ApplicationController
def new
@user = User.find(params[:user_id])
@review = @user.reviews.new(params[:for_user_id])
end
def create
@user = User.find(params[:id])
@review = current_user.reviews.build(review_params)
redirect_to root_path
end
def show
end
def index
@user = User.find(params[:for_user_id])
@reviews = Review.all
end
private
def review_params
params.require(:review).permit(:user_id, :user_id, :content)
end
end
and my view
<%= form_for([@user, @user.reviews.build]) do |f| %>
<%= f.text_area :content, placeholder: "Your review" %>
<%= f.submit "Go", class: "btn btn-large btn-primary" %>
<% end %>
all work, but no data send to the db :\ what i doing wrong?
Upvotes: 0
Views: 87
Reputation: 3741
I think you're missing two things. The User and Review classes both need to reference the UserReview class that they employ in the through relationship, e.g.,
class User < ActiveRecord::Base
...
has_many :user_reviews_received, class_name: 'UserReview', foreign_key: :for_user_id
has_many :reviews_received, through: :user_reviews_received, class_name: 'Review'
has_many :user_reviews_written, class_name: 'UserReview', foreign_key: :by_user_id
has_many :reviews_written, through: :user_reviews_written, class_name: 'Review'
...
end
As noted above, the create action seems a bit confused. Generally speaking the params should be the same for building up an instance in the new and create actions but you've got some differences. You could resolve this in one of two ways. One option would be to resolve it in the controller.
class ReviewsController < ActionController::Base
def new
@user = User.find(params[:user_id])
@review = @user.reviews_received.new(by_user_id: current_user.id)
end
def create
@review = @user.reviews_received.create(params[:review].merge(by_user_id: current_user.id))
redirect_to root_path
end
end
The second option would be to resolve it in the view (new first line in the form).
<%= form_for([@user, @user.reviews_received.build(by_user_id: current_user.id)]) do |f| %>
<%= f.hidden_field :by_user_id %>
<%= f.text_area :content, placeholder: "Your review" %>
<%= f.submit "Go", class: "btn btn-large btn-primary" %>
<% end %>
I would tend towards something like the first option
Upvotes: 1
Reputation: 13354
You're not saving anything in the create
method, therefore nothing is going to persist.
You'll want something like:
def create
@user = User.find(params[:id])
@review = @user.reviews.build(review_params)
if @user.save && @review.save
redirect_to root_path
else
(handle bad data)
end
end
I would also tend to agree with @marzapower - If you want to use current_user
, you don't need the line above @review
. My method above has this change included.
Upvotes: 3
Reputation: 5611
There's an error in the controller, I think:
def create
@user = User.find(params[:id])
@review = @user.reviews.build(review_params)
@review.save
redirect_to root_path
end
You were creating new Review
s for current_user
instead of @user
.
Upvotes: 0