Mailboxer Gem, Admin View - ruby-on-rails

I'm using the mailboxer gem for conversations/messages between the User model in my app. This is all working fine, thanks to some great help in stack overflow. I'm now trying to setup a section so admin can view all the conversations that are happening.
I have created a controller and view for conversations, nested in my admin section. I've pulled in all conversations on the index page with:
def index
#admin_conversations = Conversation.all
end
This has listed all the conversations, and a link to show each conversation, as expected.
The problem I am having, is that the mailboxer Gem is setup to only allow the current_user to view conversations that the current_user is a participant in. So I can click some of the conversations, (signed is as an admin) and see the contents, but some (that are between other test users) I cannot see i.e it throws an exception such as:
Couldn't find Conversation with id=5 [WHERE "notifications"."type" = 'Message' AND "receipts"."receiver_id" = 35 AND "receipts"."receiver_type" = 'User']
How can I define the method in my admin controller so that the admin can see everything?
I'm currently using cancan and allowing all 3 user roles I have (admin, client and supplier) like this:
can :manage, Conversation
...so it isn't a normal authorisation problem.
Here is my conversations controller:
class ConversationsController < ApplicationController
authorize_resource
helper_method :mailbox, :conversation
def create
recipient_emails = conversation_params(:recipients).split(',')
recipients = User.where(email: recipient_emails).all
conversation = current_user.
send_message(recipients, *conversation_params(:body, :subject)).conversation
redirect_to :back, :notice => "Message Sent! You can view it in 'My Messages'."
end
def count
current_user.mailbox.receipts.where({:is_read => false}).count(:id, :distinct => true).to_s
end
def reply
current_user.reply_to_conversation(conversation, *message_params(:body, :subject))
redirect_to conversation
end
def trash
conversation.move_to_trash(current_user)
redirect_to :conversations
end
def untrash
conversation.untrash(current_user)
redirect_to :conversations
end
private
def mailbox
#mailbox ||= current_user.mailbox
end
def conversation
#conversation ||= mailbox.conversations.find(params[:id])
end
def conversation_params(*keys)
fetch_params(:conversation, *keys)
end
def message_params(*keys)
fetch_params(:message, *keys)
end
def fetch_params(key, *subkeys)
params[key].instance_eval do
case subkeys.size
when 0 then self
when 1 then self[subkeys.first]
else subkeys.map{|k| self[k] }
end
end
end
end
The answer is probably something pretty silly, but I am new to this...
Thanks

In your conversation method, your calling mailbox.conversations.find(params[:id])
mailbox.conversations is what is limiting you to the current user's conversations.
Try just Conversation.find(params[:id])

Related

Add custom attributes in the mailboxer gem

I have used mailboxer gem for the messaging between users in my website.
Which is based on spree module.
I want to add the product id with the conversation so user can filter the conversations according to the products.
How can I achieve this?
Here is the code for message_controller file:
module Spree
module Admin
class MessagesController < Spree::BaseController
before_action :authenticate_spree_user!
def index
filtered_messages = Mailboxer::Message.ads_id(params[:ad_id])
end
def new
#chosen_recipient = Spree::User.find_by(id: params[:to].to_i) if params[:to]
end
def create
product_id = params[:product_id]
recipients = Spree::User.where(id: params['recipients'])
conversation = current_spree_user.send_message(recipients, params[:message][:body], params[:message][:subject], params[:product_id]).conversation
flash[:success] = 'Message has been sent!'
redirect_to '/admin/conversations'
end
private
def conversation_params
#params.require(:mailboxer_conversations).permit(:ad_id)
params.permit(:ad_id)
end
end
end
end

Adding search function for gem mailboxer

I'm new to Rails, and I found this gem mailboxer for sending messages between the website users. I am unable to write the search functions for inbox and sent.
conversations controller
class ConversationsController < ApplicationController
before_action :authenticate_user!
def new
end
def create
recipients = User.where(id: conversation_params[:recipients])
conversation = current_user.send_message(recipients, conversation_params[:body], conversation_params[:subject]).conversation
flash[:success] = "Your message was successfully sent!"
redirect_to conversation_path(conversation)
end
def show
#receipts = conversation.receipts_for(current_user)
# mark conversation as read
conversation.mark_as_read(current_user)
end
def reply
current_user.reply_to_conversation(conversation, message_params[:body])
flash[:notice] = "Your reply message was successfully sent!"
redirect_to conversation_path(conversation)
end
def trash
conversation.move_to_trash(current_user)
redirect_to mailbox_inbox_path
end
def untrash
conversation.untrash(current_user)
redirect_to mailbox_inbox_path
end
private
def conversation_params
params.require(:conversation).permit(:subject, :body,recipients:[])
end
def message_params
params.require(:message).permit(:body, :subject)
end
end
What do I need to do to implement these?
I am not aware of the gem you are talking about. However, in general, you could do something like this in Rails.
Assuming you have a model Message, with name as a column, you could do this:
Message.where("name like ?", params[:name])
where params[:name] could be either "inbox" or "sent".

Keep Receiving an "Unknown attribute=user_id" error

First time poster, long time lurker here. I have a Users model and controller for a little video game application for Rails that I'm currently making. So I've read a couple of answers on here regarding this issue, but none of the answers really seem to have helped me. People have suggested adding a "user_id" column to my Users table, but my point of contention is, I thought the "user_id" was automatically made in Rails? Even if I use a user.inspect, I still see a user_id=7show up on the page. However, I still get the unknown attribute error when attempting to create a game and assign to the current user. Any help would be most appreciated in pinpointing the cause and solution to this. Thanks!
app/controllers/users_controller.rb:
class UsersController < ApplicationController
skip_before_filter :require_authentication, only: [:new, :create]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
#user = current_user
end
def create
#user = User.create!(user_params)
session[:user_id] = #user.id
redirect_to users_path, notice: "Hi #{#user.username}! Welcome to DuckGoose!"
end
def update
current_user.update_attributes!(user_params)
redirect_to users_path, notice: "Successfully updated profile."
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_url, notice: 'User was successfully destroyed.'
end
private
def user_params
params.require(:user).permit(:username, :firstname, :lastname, :email, :password, :password_confirmation)
end
end
app/config/routes.rb:
NkuProject::Application.routes.draw do
resources :users do
resources :games
end
resources :sessions
resources :games
get "sign_out", to: "sessions#destroy"
get "profile", to: "users#edit"
root to: "sessions#new"
end
app/controllers/games_controller.rb
class GamesController < ApplicationController
def new
#game = Game.new
end
def index
#games = Game.all
end
def destroy
#game = Game.find(params[:id])
#game.destroy
redirect_to games_url, notice: 'Game was successfully deleted.'
end
def create
#game = current_user.games.build(game_params)
if #game.save
redirect_to #game, notice: "Game successfully added"
else
render :new
end
end
def show
#game = Game.find(params[:id])
end
private
def game_params
params.require(:game).permit!
end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :require_authentication
def current_user
#current_user ||= User.find_by(id: session[:user_id]) if session[:user_id].present?
end
helper_method :current_user
def require_authentication
if current_user
true
else
redirect_to new_session_path
end
end
end
I'm sure I'm missing some code to put in for reference, but if I need anything else please let me know.
Looking at the way your controller actions are defined, I can safely say that User and Game have a 1-M relationship, i.e.,
class User < ActiveRecord::Base
has_many :games
end
class Game < ActiveRecord::Base
belongs_to :user
end
Now, based on that games table must have a field named user_id. Rails is not going to create it for you unless you specify it. You need to add field user_id in games table by creating a migration for the same. Right now, it doesn't seem like you have user_id foreign_key field in games table. Hence, the error while saving games record.

Show username on Mailboxer inbox in Rails

I'm using the Mailboxer (https://github.com/ging/mailboxer) gem in my Rails app to handle private messages between users. As per the documentation, I'm using = render mailbox.inbox to show a list of all conversations (messages) for the logged-in user. However, the method only outputs the subject of the message. I need to show the sender of the message along with the subject. How can I edit this output so that the sender name is displayed?
The SQL table shows that the sender name is not stored in the conversations table, but on the notifications table via notifications_on_conversation_id (one to many). I tried to use <%= conversation.notifications.sender_id %> but I got the following error:
NoMethodError in Conversations#index
undefined method `notifications' for nil:NilClass
What can I add to the conversation controller and view in order to display the conversation's user and subject?
Thanks!
Conversations controller:
class ConversationsController < ApplicationController
before_filter :authenticate_user!
helper_method :mailbox, :conversation
def create
recipient_emails = conversation_params(:recipients).split(',')
recipients = User.where(email: recipient_emails).all
conversation = current_user.
send_message(recipients, *conversation_params(:body, :subject)).conversation
redirect_to conversation
end
def reply
current_user.reply_to_conversation(conversation, *message_params(:body, :subject))
redirect_to conversation
end
def trash
conversation.move_to_trash(current_user)
redirect_to :conversations
end
def untrash
conversation.untrash(current_user)
redirect_to :conversations
end
private
def mailbox
#mailbox ||= current_user.mailbox
end
def conversation
#conversation ||= mailbox.conversations.find(params[:id])
end
def conversation_params(*keys)
fetch_params(:conversation, *keys)
end
def message_params(*keys)
fetch_params(:message, *keys)
end
def fetch_params(key, *subkeys)
params[key].instance_eval do
case subkeys.size
when 0 then self
when 1 then self[subkeys.first]
else subkeys.map{|k| self[k] }
end
end
end
end
sender_id is available using receipt.notification.sender_id and .sender_type
for any conversation you can retrieve the receipts using:
#receipts = conversation.receipts_for
I ran on the same issue at some point and my solution was something like this: accessing current_user in mailboxer mailer notification

before_destroy in rails, little help need!

i have table called users, if i want to delete some user (User can add questions and add respondents (who will answer on his questions)), i need to delete him and get his id to people who deleted this person. So for example:
Sure.
def destroy_and_transfer_to(user)
transaction do
questions.each do |q|
q.update_attribute(:user_id => user)
end
respondents.each do |r|
r.update_attribute(:user_id => user)
end
destroy
end
end
Now use this method instead of the "destroy" method.
OR
you can stick to callbacks like this
before_destroy :transfer_to
attr_accessor :user_who_takes_over
private
def transfer_to
if user_who_takes_over
questions.each do |q|
q.update_attribute(:user_id => user_who_takes_over)
end
respondents.each do |r|
r.update_attribute(:user_id => user_who_takes_over)
end
end
end
Then you can :
#user.user_who_takes_over = current_user
#user.destroy
Just a couple of ideas! Good Luck!
Update: All the code i provided above belongs in your model.
In your controller you need to have a destroy method
in your controller
def destroy
user = User.find(params[:id])
user.user_who_takes_over = current_user
if user.destroy
flash[:notice] = "User destroyed, all stuff transferred"
else
Rails.logger.debug(user.errors.inspect)
flash[:error] = "Error destroying user"
end
redirect_to :back
end
Change to suite your need of course!

Resources