Makcheese Makcheese - 1 year ago 40
Ruby Question

Polymorphic Routes with Custom Actions in Rails

So I am making a chat app, and I want users to be able to leave chat rooms. This would be done by posting a delete request to a route like

/users/:id/chat_rooms/leave/:chat_room_id
.

The Users model has
has_many :chat_rooms, through: chat_room_users
while ChatRooms has
has_many :users, through chat_room_users
. The UsersController has a
leave
action, which I want to call using this request on this url.

I want to create a link to this url on a view that I have. I already have a variable
@user
for the current user and
@chosen
for the current chat room available on the view. So how would I do a link_to and route for this setup? I have
delete /users/:id/chat_rooms/leave/:chat_room_id
in the routes.rb file, but how would I do the link_to?

Thank you.

max max
Answer Source

You're overcomplicating it.

DELETE /chat_rooms/:chat_room_id/leave

Instead of passing the user id via the URL you should instead get it through the session or a token (if its an API app).

Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason). http://weblog.jamisbuck.org/2007/2/5/nesting-resources

This is just a loose example of how to solve this:

# routes.rb
resources :chat_rooms do
  member do
    post :join
    delete :leave
  end
end

class User
  has_many :chat_room_users 
  has_many :chat_rooms, though: :chats
end

class ChatRoomUser
  belongs_to :user
  belongs_to :chatroom
end

class ChatRoom
  has_many :chats
  has_many :users, though: :chats
end

Putting this in UsersController is pretty questionable. I would instead place it in ChatroomsController.

class ChatroomsController   
  # ...
  # POST /chat_rooms/:chat_room_id/join
  def join
    @chat_room = ChatRoom.find(params[:id])
    @chat = current_user.chat_room_users.new(chat_room: @chat_room)

    if @chat_room.create
      # ...
    else
      # ...
    end
  end
  # DELETE /chat_rooms/:chat_room_id/leave
  def leave
    @chat_room = ChatRoom.find(params[:id])
    @chat = current_user.chat_room_users.find_by(chat_room: @chat_room)
    @chat.destroy
  end
end

<%= button_to 'Join', join_chat_room_path(@chat_room), method: :post %>
<%= button_to 'Leave', leave_chat_room_path(@chat_room), method: :delete %>
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download