Reputation:
I have the following models:
class Blog < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :blog
end
Right now I have only two routes:
/blogs/:blog_id/posts
- to create a post/posts/id:
- to update a postI'm not sure if I should change the second one to also accept a :blog_id
. The update method (on the controller) doesn't need to use the site to update a post:
class PostsController < ApplicationController
before_action :set_site, only: [:create]
before_action :set_post, only: [:update]
PERMITED_POST_PARAMS = [
:post_id,
:title,
:url,
:body
].freeze
def create
@post = @site.posts.build(post_params)
if @post.save
render json: @post, status: :created
else
render json: @post.errors, status: :unprocessable_entity
end
end
def update
if @post.update(post_params)
render json: @post
else
render json: @post.errors, status: :unprocessable_entity
end
end
private
def post_params
params.require(:post).permit(*PERMITED_POST_PARAMS)
end
def set_post
@post = Post.find(id)
end
def set_site
@site = Site.find(site_id)
end
def post_id
params[:post_id]
end
def id
params[:id]
end
end
My question is: is it ok to do what I'm doing, or it a bad practice?
Thank you.
Upvotes: 0
Views: 51
Reputation: 15838
As always, it depends. It's ok to do what you want, it's also ok to have the update nested inside the other model (it's confusing that you have "blog_id" on the route and your helpers are "post_id" and "id" but you call "id" to find a post and "site_id" which is not defined (??)).
Rails route helpers will automatically create the update nested inside the site if you do something like:
resources :blogs do
resources :posts
end
You don't really need the blog_id, but you can use that as an extra filtering measure: if you have the blog_id, you can do @post = @blog.posts.find(...)
instead of @post = Post.find(...)
.
Is it needed? no, but it gives you context and consistency on your routes (really opinionable of course).
(Why are you permitting post_id??)
Upvotes: 0
Reputation: 6628
I'm not sure if this answer is more like an opinion, but I'd say yes - keep it simple.
To create a post you need a :blog_id
so a nested resource is one way to do it. Other would be POST /post
and pass the :blog_id
in the POST params.
Both seem perfectly fine, and it's up to you to design your API. The biggest rule: keep it consistent.
That being said - I can't recall single API that I was using, which used the nested resources for the create/update methods. It seems awkward: if I create a post - why one attribute of it (blog_id
) should go in the path, and rest should be sent as params?
On the other hand nested resources work great for the read methods:
/post/1/comments
instead of /comments?post_id=1
Is has more natural fell to it - access resource /post/1
and subresources as a sub path /post/1/author
, /post/1/tags
But create resources directly POST /tags
, post /comments
with the attributes passed on as params.
Upvotes: 1