I am looking to model a messaging system.
At the moment I have two models, User and Message. I wish for there to be multiple associations on a message to a user, the sender and receiver.
This is my active record migration for my Message.
class CreateMessages < ActiveRecord::Migration[5.1]
def change
create_table :messages do |t|
t.string :body
t.belongs_to :sender, :class_name=>'User', :foreign_key=>'sent_from'
t.belongs_to :recipient, :class_name=>'User', :foreign_key=>'sent_to'
t.timestamps
end
end
end
However when I attempt to create a new Message I get the following error:
class DashboardController < ApplicationController
before_action :authenticate_user!
def index
Message.create(body: "Hello World", 1, 2)
end
end
However I get the following error
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: main.recipients: INSERT INTO "messages" ("body", "created_at", "updated_at") VALUES (?, ?, ?)):
What am I missing here? What is the best way to model this relationship?
A few things wrong here.
According to the docs, belongs_to (which is an alias for references) in a migration takes the options: :type, :index, :foreign_key, :polymorphic, and :null. There is no :class_name, and :foreign_key should be true or false (defaults to false).
So, your migration should probably look more like:
class CreateMessages < ActiveRecord::Migration[5.1]
def change
create_table :messages do |t|
t.string :body
t.belongs_to :sender
t.belongs_to :recipient
t.timestamps
end
end
end
message.rb will look something like:
class Message < ActiveRecord::Base
belongs_to :sender, class_name: 'User'
belongs_to :recipient, class_name: 'User'
...
end
I don't know why you're creating a Message in the index action of your DashboardController. But, hey, whatever floats your boat.
But, it should probably look more like:
class DashboardController < ApplicationController
before_action :authenticate_user!
def index
Message.create(body: "Hello World", sender_id: 1, recipient_id: 2)
end
end
Or, it might look something like:
class DashboardController < ApplicationController
before_action :authenticate_user!
def index
sender = User.find_by(...)
recipient = User.find_by(...)
Message.create(body: "Hello World", sender: sender, recipient: recipient)
end
end
Rails can be pretty smart, but when you do:
Message.create(body: "Hello World", 1, 2)
it's not so smart to know whether 1 is a sender or a recipient. Same with 2. You need to tell rais which is which.
Related
I am using Ruby on Rails API with Postgresql I have two models subject and teacher, which has a relation "many to many", so using intermediate table subject_teacher. I want to create a map where which teacher is teaching which subject. All I want to store the ID's of teacher and subject in front of each other so that I can fetch them using JOIN later. (or suggest any other alternative).
Using Ruby on Rails 6.1
MIGRATIONS
Teacher
class CreateApiV1Teacher < ActiveRecord::Migration[6.1]
def change
create_table :api_v1_teacher do |t|
t.string :name
t.timestamps
end
end
end
Subject
class CreateApiV1Subject < ActiveRecord::Migration[6.1]
def change
create_table :api_v1_subject do |t|
t.string :name
t.timestamps
end
end
end
Subject Teacher
class CreateApiV1SubjectTeacher < ActiveRecord::Migration[6.1]
def change
create_table :api_v1_subject_teacher do |t|
t.belongs_to :teacher
t.belongs_to :subject
t.timestamps
end
end
end
MODEL
Teacher
class Api::V1::Teacher < ApplicationRecord
has_many :subject_teacher
has_many :subject, :through => :subject_teacher
end
Subject
class Api::V1::Subject < ApplicationRecord
has_many :subject_teacher
has_many :teacher, :through => :subject_teacher
end
SubjectTeacher
class Api::V1::SubjectTeacher < ApplicationRecord
belongs_to :teacher
belongs_to :subject
end
CONTROLLER (Post Method)
I want to take array from front-end and save entries in DB (or any other alternative to make things faster ?)
class V1::SubjectTeacherController < ApplicationController
before_action :set_api_v1_subject_teacher, only: [:show, :update, :destroy]
def create
#api_v1_subject = Api::V1::SubjectTeacher.new(api_v1_my_subject_teacher)
if #api_v1_subject.save
render json: #api_v1_subject, status: :created, location: #api_v1_subject
else
render json: #api_v1_subject.errors, status: :unprocessable_entity
end
end
def api_v1_my_subject_teacher
params.require(:my_ids).permit([:teacher_id, :subject_id])
end
end
JSON
{
"my_ids": [
{
"teacher_id": 1,
"subject_id": 2
},
{
"teacher_id": 1,
"subject_id": 3
}
]
}
I am new to Ruby on Rails and backend any other alternative method or new way will be a great help.
Thank you
I used this guide as a starting point for creating a messaging system from scratch. I had to modify these to handle messages between User and AdminUser. For some reason, whenever I now try to create a new conversation by clicking in my view the following link:
<li><%= link_to admin.email, conversations_path(sendable_id: current_user.id, recipientable_id: admin.id), method: :post %></li>
I encounter the error:
ActionController::ParameterMissing (param is missing or the value is empty: conversation
Did you mean? controller
authenticity_token
action
recipientable_id):
Params are:
=> #<ActionController::Parameters {"_method"=>"post", "authenticity_token"=>"pHmi9kWBLSc5QSJUPQxfNsqSR1fqWCSCBqEVgRMljhgrxB9g4M0ClsdEi2hBLCTjrLLl774T-mnyK8m40LFhNA", "recipientable_id"=>"1", "sendable_id"=>"2", "controller"=>"conversations", "action"=>"create"} permitted: false>
I am directed to the params.permit line in my controller:
class ConversationsController < BaseController
def index
#users = User.all
#admins = AdminUser.all
#conversations = Conversation.all
end
def create
#conversation = if Conversation.between(params[:sendable_id], params[:recipientable_id]).present?
Conversation.between(params[:sendable_id], params[:recipientable_id]).first
else
Conversation.create!(conversation_params)
end
redirect_to conversation_messages_path(#conversation)
end
private
def conversation_params
params.require(:conversation).permit(:sendable_id, :recipientable_id)
end
end
If I remove require(:conversation) I'll get an error:
Validation failed: Sendable must exist, Recipientable must exist
Models:
class User < ApplicationRecord
has_many :conversations, as: :sendable
has_many :conversations, as: :recipientable
end
class AdminUser < ApplicationRecord
has_many :conversations, as: :sendable
has_many :conversations, as: :recipientable
end
class Conversation < ApplicationRecord
belongs_to :sendable, polymorphic: true
belongs_to :recipientable, polymorphic: true
has_many :messages, dependent: :destroy
validates :sendable_id, uniqueness: { scope: :recipientable_id }
end
class Message < ApplicationRecord
belongs_to :conversation
belongs_to :messageable, polymorphic: true
validates_presence_of :body
end
schema:
create_table "conversations", force: :cascade do |t|
t.string "sendable_type"
t.bigint "sendable_id"
t.string "recipientable_type"
t.bigint "recipientable_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["recipientable_type", "recipientable_id"], name: "index_conversations_on_recipientable"
t.index ["sendable_type", "sendable_id"], name: "index_conversations_on_sendable"
end
You need to help Rails understand which polymorphic models you are referencing; if you only provide ids it fails because Rails also needs the polymorphic type (remember: the type is mandatory so Rails can make the link to the actual table. In your case there are two possible types User and AdminUser)
Simply provide the polymorphic types and also add them to the conversation_params method. From looking at your code I'm guessing this is what you're after:
<li><%= link_to admin.email, conversations_path(sendable_id: current_user.id, sendable_type: 'User', recipientable_id: admin.id, recipientable_type: 'AdminUser'), method: :post %></li>
So I have a couple of models in my app and they are all registered with ActiveAdmin. They all work great except for one and I can't figure out why. I keep getting the same error:
NameError at /admin/reports
uninitialized constant Report::Users
The model that it is happening on is called Report
class Report < ActiveRecord::Base
belongs_to :users
belongs_to :cars
enum reason: [:accident,:totaled,:stolen]
validates :reason, presence:true
end
The controller looks like this:
Class ReportsController < ApplicationController
before_action :authenticate_user!
def create
#car=Car.find(params[:car_id])
#report=#car.reports.build(report_params)
#report.user_id=current_user.id
#report.car_id=#car.id
if #report.save
redirect_to car_path(car)
else
render 'new'
end
end
def destroy
#report=Report.find(params[:id])
#report.destroy
end
private
def report_params
params.require(:report).permit(:reason)
end
end
This is the migration used to create the model:
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.references :user, index: true
t.references :car, index: true
t.integer :reason, default: 0
t.timestamps null: false
end
add_foreign_key :reports, :users
add_foreign_key :reports, :cars
end
end
Lastly here is the active_admin app/admin/report.rb:
ActiveAdmin.register Report do
# See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
#
# permit_params :list, :of, :attributes, :on, :model
#
# or
#
# permit_params do
# permitted = [:permitted, :attributes]
# permitted << :other if resource.something?
# permitted
# end
end
I have been trying to figure it out for a couple of hours. Solutions that I saw on SO that don't work. I ran rails generate active_admin:resource Report to create it so it is singular. Why is it misbehaving?
NameError at /admin/reports uninitialized constant Report::Users
Association name for a belongs_to should be singular as per naming conventions.
class Report < ActiveRecord::Base
belongs_to :user #here
belongs_to :car #and here too
enum reason: [:accident,:totaled,:stolen]
validates :reason, presence:true
end
I am currently following Ryan Bates tutorial on activity feed from scratch.
**I added a originator_id to the database so that I can save the ID of the Owner who originated the post. But for some reason I can't get it to work.
My Database from Scratch
class CreateActivities < ActiveRecord::Migration
def change
create_table :activities do |t|
t.belongs_to :user
t.string :action
t.belongs_to :trackable
t.string :trackable_type
###I want to save the id corresponding to User who created the object
t.belongs_to :originator
t.string :originator_type
t.timestamps
end
add_index :activities, :user_id
add_index :activities, :trackable_id
add_index :activities, :originator_id
end
end
Here is my Code
Models
class Activity < ActiveRecord::Base
belongs_to :user
belongs_to :trackable, polymorphic: true
belongs_to : originator, polymorphic: true
attr_accessible :action, :recipient, :trackable
###how can i set the originator_id value
after_create :set_originator
def set_originator
self.originator.update_attribute(:originator, ???)
end
end
Controllers
class ApplicationController < ActionController::Base
###sets the action and trackable values
###how can i the originator here. i keep getting an error saying undefined method
###why is it that rails recognizes trackable?
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable,
originator: originator
end
end
class LikesController < ApplicationController
def create
#like = Like.create(params[:like])
#dailypost = #like.dailypost
###Used to call track activity method above
track_activity #like
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
Don't know how solid this answer will be as i add more models to the activities, but this worked for my likes model.
If anyone can provide another solution that will work with multiple models i would really appreciate it. :)
class ApplicationController < ActionController::Base
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable,
originator: originator
end
def originator
#like.dailypost.user
end
end
I've been searching for a while now, but google isn't really helping me.
The ArgumentError Unknown key(s): client_id appears in the ProjectsController:
# projects_controller.rb
class Management::ProjectsController < Management::ManagementController
def index
#projects = Project.find( :client_id => current_user.client )
end
end
This is the project model:
# project.rb
class Project < ActiveRecord::Base
belongs_to :client
end
This is the client model:
# client.rb
class Client < ActiveRecord::Base
has_many :projects
end
And finally, the migration:
# 20110404155917_create_projects.rb
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.string :name
t.datetime :date
t.text :description
t.integer :client_id
t.timestamps
end
end
def self.down
drop_table :projects
end
end
Should be possible, right?
Can't see what I'm missing here..
Anyone got a suggestion?
Thanks!
Use
#projects = Project.where( :client_id => current_user.client.id)
or
#projects = Project.find_by_client_id(current_user.client.id)
or you could do
#projects = current_user.client.projects
Little bit cleaner perhaps?