0

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?

Adyl
  • 39
  • 10

4 Answers4

3

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.

CDub
  • 13,146
  • 4
  • 51
  • 68
  • yep, i found this mistake, but when i fix that, rails send data to the review table, and dont send data to the users_review... users_review is empty – Adyl Nov 21 '13 at 15:45
  • See my edit. You'll want to do `@user.save` to create the association. See: http://stackoverflow.com/questions/12654040/rails-create-through-record-via-association – CDub Nov 21 '13 at 15:47
  • 1
    Since he's using `<%= form_for([@user, @user.reviews.build]) do |f| %>` with a specific user, I doubt the real target is `current_user`. It would be a misuse of nested resources routes. – marzapower Nov 21 '13 at 16:03
  • @marzapower - totally agree! – CDub Nov 21 '13 at 16:03
2

You are missing a call to the save method in your create action:

def create
     @user = User.find(params[:id])
     @review = current_user.reviews.build(review_params)
     @review.save
     redirect_to root_path
end

This post explains the difference between build and create.

Community
  • 1
  • 1
AbM
  • 7,326
  • 2
  • 25
  • 28
  • yep, i found this mistake, but when i fix that, rails send data to the review table, and dont send data to the users_review... users_review is empty – Adyl Nov 21 '13 at 15:45
1

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

AndyV
  • 3,696
  • 1
  • 19
  • 17
  • thanks, but now rails give error ActiveRecord::UnknownAttributeError in ReviewsController#create unknown attribute: for_user_id @review = @user.reviews.create(params[:review].merge(for_user_id: params[:for_user_id])) i thinks all my problems are in the db, in table users_review with for_user_id, and by_user_id – Adyl Nov 21 '13 at 16:19
  • I could only infer so much from your post so I simply tried to get the new and create actions to agree. If you have by_user_id and for_user_id in the Review model then let's update the User model to reflect that. – AndyV Nov 21 '13 at 16:26
0

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 Reviews for current_user instead of @user.

marzapower
  • 5,531
  • 7
  • 38
  • 76