Rails用户到用户消息
我对rails很新,所以请在回复中详细说明。 我正在构建一个使用设计进行身份validation的Web应用程序。 我现在停留的部分是用户消息系统。 想法是用户A登录到应用程序并可以访问用户B的配置文件,并且在用户B的配置文件上可以单击允许用户A向用户B撰写消息的链接。然后用户B可以登录到应用程序并访问收件箱中将找到用户A的消息。
我相信我在这里定义发件人和收件人角色时遇到了问题,现在我正在尝试显示用户将撰写邮件的表单。有人能看到我在这里做错了吗? 我收到以下错误。 我已经读过要做的事情就是将User_id字段添加到表中,但我希望使用sender_id和recipient_id来链接这些消息,这两个消息都等于user_id(例如,用户1 [发送者]向用户2发送消息[接受者]):
未知属性:user_id
def new @message = current_user.messages.new recipient_id:params [:sender_id] end
此外,对于铁路专家或任何与此类似的人,您能否告知我是否朝着正确的方向前进,或提供任何指导? 我在这里盲目编码,只是在我继续努力的时候试图弥补。 任何指导都会非常感激,为我节省了很多时间。 代码如下:
用户迁移
class DeviseCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| t.string :first_name t.string :last_name t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :reset_password_token t.datetime :reset_password_sent_at t.datetime :remember_created_at t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip t.string :last_sign_in_ip t.timestamps end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true end end
邮件迁移
class CreateMessages < ActiveRecord::Migration def change create_table :messages do |t| t.string :content t.integer :sender_id t.integer :recipient_id t.timestamps end end end
schema.rb
ActiveRecord::Schema.define(version: 20140909174718) do create_table "messages", force: true do |t| t.string "content" t.integer "sender_id" t.integer "recipient_id" t.datetime "created_at" t.datetime "updated_at" end create_table "users", force: true do |t| t.string "first_name" t.string "last_name" t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.datetime "created_at" t.datetime "updated_at" t.string "current_industry" t.integer "years_in_current_industry" t.string "hobbies" end add_index "users", ["email"], name: "index_users_on_email", unique: true add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end
的routes.rb
Catalyst::Application.routes.draw do devise_for :users, :controllers => { :registrations => "registrations" } devise_scope :user do get 'register', to: 'devise/registrations#new' get 'login', to: 'devise/sessions#new', as: :login get 'logout', to: 'devise/sessions#destroy', as: :logout end resources :users do member do get 'edit_profile' end resources :messages, only: [:new, :create] end resources :messages, only: [:index, :show, :destroy] root to: "home#index" match '/about', to: 'static_pages#about', via: 'get' match '/contact', to: 'static_pages#contact', via: 'get' match '/help', to: 'static_pages#help', via: 'get' match '/legal', to: 'static_pages#legal', via: 'get' end
users_controller
class UsersController < ApplicationController before_filter :authenticate_user! def index @users = User.all end def show @user = User.find(params[:id]) end def new end def create end def edit end def update @user = User.find(params[:id]) @user.update!(user_params) redirect_to @user end def destroy end def edit_profile @user = User.find(params[:id]) end def user_params params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_industry, :years_in_current_industry, :hobbies) end def sender @user = User.find(params[:id]) end def recipient @user = User.find(params[:id]) end end
messages_controller
class MessagesController < ApplicationController before_action :set_recipient def new @message = Message.new @recipient = User.find(params[:user_id]) end def create @message = Message.new message_params if @message.save flash[:success] = "Your message has been sent!" redirect_to user_messages_path else flash[:failure] = "Please try again." redirect_to users_path end end private def message_params params.require(:message).permit(:content, :sender_id, :recipient_id) end end
user.rb
class User "sender_id" has_many :to_messages, class_name: 'Message', :foreign_key => "recipient_id" devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :remember_me, :current_industry, :years_in_current_industry, :hobbies end
message.rb
class Message < ActiveRecord::Base belongs_to :sender, class_name: "User" belongs_to :recipient, class_name: "User" validates :content, presence: true, length: { maximum: 500 } validates :sender_id, presence: true validates :recipient_id, presence: true end
消息/ index.html.erb
Inbox
消息/ new.html.erb
Create Message
耙路线
user_messages POST /users/:user_id/messages(.:format) messages#create new_user_message GET /users/:user_id/messages/new(.:format) messages#new users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy messages GET /messages(.:format) messages#index message GET /messages/:id(.:format) messages#show DELETE /messages/:id(.:format) messages#destroy
楷模
#app/models/user.rb class User < ActiveRecord::Base has_many :messages, class_name: "Message", foreign_key: "recipient_id" has_many :sent_messages, class_name: "Message", foreign_key: "sender_id" end #app/models/message.rb class Message < ActiveRecord::Base belongs_to :recipient, class_name: "User", foreign_key: "recipient_id" belongs_to :sender, class_name: "User", foreign_key: "sender_id" scope :unread, -> { where read: false } end
这应该使您能够创建“属于”用户(IE收件人)的邮件,然后您可以将“发件人”配置文件与这些邮件相关联。
–
控制器
这将使您能够调用以下内容:
#app/controllers/messages_controller.rb class MessagesController < ApplicationController before_action :set_recipient, only: [:new, :create] def new @message = current_user.sent_messages.new end def create @message = current_user.sent_messages.new message_params @message.recipient_id = @recipient.id @message.save end def index @messages = current_user.messages end def destroy @message = current_user.messages.destroy params[:id] end def show @message = current_user.messages.find params[:id] end private def message_params params.require(:message).permit(:content, :recipient_id, :sender_id) end def set_recipient @recipient = User.find params[:user_id] end end
-
路线
#config/routes.rb devise_for :users, path: "", controllers: { :registrations => "registrations" }, path_names: {sign_up: "register", sign_in: "login", sign_out: "logout"} resources :users do get :profile resources :messages, only: [:new, :create] #-> domain.com/users/:user_id/messages/new end resources :messages, only: [:index, :show, :destroy] #-> domain.com/messages/:id
-
查看
这将使您能够使用以下链接:
#app/views/users/show.html.erb (user to send message to) <%= link_to "Send Message", user_messages_path(@user.id) %> #app/views/messages/new.html.erb <%= form_for [@recipient, @user] do |f| %> <%= f.text_field :content %> <%= f.submit %> <% end %> #app/views/messages/index.html.erb Inbox
<% @messages.each do |message| %> <%= message.content %> <% end %>
-
固定
我已经读过要做的事情就是将User_id字段添加到表中,但我希望使用sender_id和recipient_id来链接这些消息,这两个消息都等于user_id(例如,用户1 [发送者]向用户2发送消息[接受者])
您不需要将user_id
添加到表中。 user_id
只是一个foreign_key
,您已在models
重写。
您需要做的就是设置我们在create
方法中执行的recipient_id
和sender_id
:
def create @message = current_user.message.new message_params @message.recipient_id = @recipient.id @message.save end
你在这里做了一些非常聪明的事情。
首先,您通过调用current_user.messages
隐式设置sender_id
外键。 如果您调用了Message.new
,那将是一个完全不同的故事(必须设置sender_id
)
其次,因为您正在使用嵌套路由,所以您将能够使用您在before_action
方法中设置的@recipient
变量来为我们提供recipient_id
的id
。
这应该适合你。 除非您尝试访问子/嵌套模型中的“父”模型数据,否则不需要使用inverse_of
。
建议
你正在做的是完全有效的
核心技巧是确保您的Message
模型与User
完全独立且独立。 这是通过您的设置实现的,允许您创建所需的各种对象。
您需要考虑的另一个方面是如何确保您能够为用户提供具有“线程”消息的能力。 您将使用其中一个层次结构gem( Ancestry
或Closure_Tree
实现此Closure_Tree
添加此function将更加深入。 如果您需要,我可以提供信息(只需发表评论)
穿线
层次结构gem实际上相对简单易用。
“踩踏”你的消息的诀窍是使用其中一个gem( Ancestry
或Closure_Tree
),因为它们为你提供了可以调用你的物品的“方法”。 它们通过在数据库中创建多个列来工作,在保存/创建所需对象时填充它们
“线程”问题是一个很大的问题,因为没有“层次结构”gem,您将无法调用所需记录的“子”对象,从而防止线程发生。 这是一个很好的Railscast如何实现它:
这个的诀窍是使用一种叫做“递归”的东西
递归是您创建“无限期”循环的地方,就数据的“递归”方式而言。 EG如果你有一个带孩子的物体,你必须递归地遍历孩子们,然后是孩子们的孩子,直到你达到显示所有数据的程度:
递归是以自相似的方式重复项目的过程。 例如,当两个镜子的表面彼此完全平行时,出现的嵌套图像是无限递归的forms。
因此,这是你如何做到这一点:
- 确保使用正确的父项保存对象
- 要显示“线程”对话,请循环访问这些父对象
- 使用递归循环遍历其子项
我们使用ancestry
gem,它存储的层次结构与我们发现的closure_tree
gem略有不同(打算很快使用closure tree gem)。
因此,您首先必须自己保存任何层次结构:
这将允许您保存该对象的各种“父”。 这意味着当您加载对象并希望循环其后代时,您将能够使用Ancestry对象方法 :
这意味着您将能够使用以下内容:
#app/views/comments/index.html.erb <%= render partial: "comments", locals: { collection: @comments } %> #app/comments/_comments.html.erb <% collection.arrange.each do |comment, sub_item| %> <%= link_to comment.title, comment_path(comment) %> <% if category.has_children? %> <%= render partial: "category", locals: { collection: category.children } %> <% end %> <% end %>
要解决您的错误,请尝试在模型类中设置has_many
和belongs_to
语句的:inverse_of
属性。 你最终可能有两个has_many
– 每个belongs_to
反向:
user.rb: has_many :from_messages, :class_name => 'Message', :foreign_key => "sender_id", :inverse_of => :sender has_many :to_messages, :class_name => 'Message', :foreign_key => "to_id", :inverse_of => :recipient message.rb: belongs_to :sender, :class_name => 'User', :inverse_of => :from_messages belongs_to :recipient, :class_name => 'User',:inverse_of => :to_messages
总的来说,我认为您的方法是消息传递系统的良好起点。 您可以尝试将代码发布到https://codereview.stackexchange.com/进行详细审核。