Reputation: 151
I'm using has_many through relationship and I don't really get what should I do else to make it work. I suppose there is something about parameters that I don't understand and omit. If so, please tell me where and how to write it, because I'm confused a little bit because of all these params. book.rb:
class Book < ActiveRecord::Base
has_many :user_books
has_many :users, through: :user_books
end
user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
validates :full_name, presence: true
has_many :user_books
has_many :books, through: :user_books #books_users - book_id user_id
end
and books_controller.rb:
class BooksController < ApplicationController
before_action :is_admin?, except: [:show_my_books, :book_params]
before_filter :authenticate_user!
expose(:book, attributes: :book_params)
expose(:user_book)
expose(:user_books)
expose(:books){current_user.books}
def create
if book.save
redirect_to(book)
else
render :new
end
end
def update
if book.save
redirect_to(book)
else
render :edit
end
end
def show
end
def is_admin?
if current_user.admin?
true
else
render :text => 'Who are you to doing this? :)'
end
end
def book_params
params.require(:book).permit(:name, :author, :anotation, user:[:name])
end
end
When I create new book it gives me an error
Couldn't find Book with 'id'=27 [WHERE "user_books"."user_id" = ?]
<%=book.name%>
Sorry for a silly question, but I couldn't find a proper example to understand it myself that's why I ask you for help. Every help would be appreciated, thank you!
Upvotes: 1
Views: 1945
Reputation: 102318
To setup a relation via a form you usually use a select or checkbox and pass the ID(s) of related item(s):
For a one to one relation the request would look like this:
POST /books { book: { name: 'Siddharta', author: 'Herman Hesse', user_id: 1 } }
For many to many or one to many you can use _ids
:
POST /books { book: { name: 'Siddharta', author: 'Herman Hesse', user_ids: [1,2,3] } }
ActiveRecord creates a special relation_name_ids=
setter and getter for has_many
and HABTM relations. It lets you modify the relations of an object by passing an array of IDs.
You can create the form inputs like so:
<%= form_for(@book) do |f| %>
<%= f.collection_select(:author_ids, User.all, :id, :name, multiple: true) %>
OR
<%= f.collection_checkboxes(:author_ids, User.all, :id, :name) %>
<% end %>
To whitelist the user_ids
params which should permit an array of scalar values and not a nested hash we pass an empty array:
def book_params
params.require(:book).permit(:name, :author, :anotation, user_ids: [])
end
On the other hand if you want to assign records to the current user it is better to get the user from the session or a token and avoid passing the param at all:
def create
@book = current_user.books.new(book_params)
# ...
end
This lets you avoid a pretty simple hack where a malicious user passes another users id or takes control of a resource by passing his own id.
As to your other error why it would try to create a strange query some sort of stack trace or log is needed.
However if you are new to Rails you might want to hold off a bit on the decent exposure gem. It obscures away a lot of important concepts in "magic" - and you'll spend more time figuring out how it works that might be better spent learning how good rails apps are built.
Upvotes: 3