Rails用户到用户消息 [英] Rails user to user messages

查看:71
本文介绍了Rails用户到用户消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Rails的新手,所以请在您的回复中进行详细说明.我正在构建一个使用devise进行身份验证的Web应用程序.我现在停留的部分是用户到用户消息传递系统.这个想法是,用户A登录到应用程序并可以访问用户B的个人资料,并且在用户B的个人资料上可以单击允许用户A撰写给用户B的消息的链接.然后,用户B可以登录到应用程序并访问收件箱中可以找到用户A的消息.

I'm very new to rails so please be detailed in your responses. I'm building a web app that uses devise for authentication. The part that I'm stuck on right now is a user to user messaging system. The idea is that User A logs into the app and can visit user B's profile, and on User B's profile can click on a link that allows User A to compose a message to User B. Then User B can log into the app and visit the inbox where User A's message will be found.

我认为我在这里定义发件人和收件人角色时遇到麻烦,现在我正尝试显示用户将其邮件写入其中的表格.有人在这里看到我在做什么错吗?我收到以下错误.我已经读到,要做的事情是将User_id字段添加到表中,但是我希望使用sender_id和receive_id来将这些消息链接起来,二者都等于user_id(例如,用户1 [sender]向用户2发送一条消息[收件人]):

I believe that I'm having trouble defining the sender and recipient roles here, right now I'm trying to display the form that users will compose their message in. Can anyone see what I'm doing wrong here? I get the following error. I've read that the thing to do is add the User_id field to the table, but I'm hoping to link this messages up using sender_id and recipient_id, which both equal user_id (e.g. User 1[sender] sends a message to User 2 [recipient]):

未知属性:user_id

unknown attribute: user_id

def新 @message = current_user.messages.new收件人ID:params [:sender_id] 结束

def new @message = current_user.messages.new recipient_id: params[:sender_id] end

此外,对于您的Rails专家或进行过类似操作的任何人,您能否建议我是否朝着正确的方向发展,或者提供任何指导?在这里,我有点盲目地编码,只是随着我的前进而尝试对其进行弥补.我相信,任何指导将不胜感激,并且可以为我节省很多时间.下面的代码:

Additionally, for you rails experts or anyone that has done something similar to this, can you advise whether or not I'm going in the right direction, or offer any guidance? I'm sort of coding blind here and just trying to make it up as I go along. Any guidance would be hugely appreciated and save me a lot of time i'm sure. Code below:

用户迁移

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

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

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

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

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 < ActiveRecord::Base
  has_many :from_messages, class_name: 'Message', :foreign_key => "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

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

messages/index.html.erb

messages/index.html.erb

<h2>Inbox</h2>

messages/new.html.erb

messages/new.html.erb

<h1>Create Message</h1>

<%= form_for [@recipient, @message] do |f| %>

    <%= f.hidden_field :recipient_id, value: @recipient.id %>

    <%= f.label "Enter your message below" %><br />
    <%= f.text_area :content %>

    <%= f.submit "Send" %>
<% end %>

耙道

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

这应该使您能够创建属于用户(即收件人)的消息,然后可以将发件人"配置文件与这些消息相关联.

This should give you the ability to create messages which "belong" to a user (IE the recipient), and then you can associate a "sender" profile to those messages.

-

控制器

这将使您能够调用以下内容:

This will give you the ability to call the following:

#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

-

观看次数

这将使您能够使用以下链接:

This will give you the ability to use the following links:

#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
<h2>Inbox</h2>
<% @messages.each do |message| %>
   <%= message.content %>
<% end %>

-

修复

我已经读到,要做的就是将User_id字段添加到表中, 但我希望使用sender_id和 收件人ID,都等于user_id(例如,用户1 [发送者]发送一个 给用户2 [收件人]的邮件)

I've read that the thing to do is add the User_id field to the table, but I'm hoping to link this messages up using sender_id and recipient_id, which both equal user_id (e.g. User 1[sender] sends a message to User 2 [recipient])

无需user_id添加到表中. user_id只是 foreign_key ,您已将其覆盖在models中.

You don't need to add user_id to your table. user_id is merely a foreign_key, which you've overridden in your models.

您需要做的就是设置recipient_idsender_id,这是我们在create方法中所做的:

All you need to do is set the recipient_id and sender_id, which we're doing in the create method:

def create
   @message = current_user.message.new message_params
   @message.recipient_id = @recipient.id
   @message.save
end

您在这里做了一些非常聪明的事情.

You've done some very clever things here.

首先,您已经通过调用current_user.messages隐式设置了sender_id外键.如果您呼叫了Message.new,那将是一个完全不同的故事(必须设置sender_id)

Firstly, you have implicitly set the sender_id foreign key by calling current_user.messages. If you had called Message.new, it would have been a completely different story (having to set sender_id)

第二,由于您使用的是嵌套路由,因此可以使用在before_action方法中设置的@recipient变量为recipient_id提供id.

Secondly, because you're using nested routes, you'll be able to use the @recipient variable you've set in the before_action method to give us the id for the recipient_id.

这应该为您工作.除非您尝试访问子/嵌套模型中的父"模型数据,否则无需使用inverse_of.

This should work for you. You won't need to use inverse_of unless you are trying to access "parent" model data in a child / nested model.

建议

您正在做的事情是完全有效的

What you're doing is completely valid

核心诀窍是确保您的Message模型是完全独立的&独立于您的User.这可以通过设置来实现,允许您创建所需的各种对象.

The core trick is to make sure your Message model is completely separate & independent to your User. This is achieved with your setup, allowing you to create the various objects that you require.

您需要考虑的另一方面是如何确保能够为用户提供线程化"消息.您将使用以下层次结构之一实现此目标: Ancestry

The other aspect you need to consider is how you're going to ensure you're able to provide the users with the ability to have "threaded" messages. You'll achieve this using one of the hierarchy gems, either Ancestry or Closure_Tree

添加此功能将更加深入.如果您需要,我可以提供信息(只需发表评论)

Adding this functionality will be a little more in-depth. I can provide information if you require (just leave a comment)

线程

层次结构的gem实际上相对易于使用.

The hierarchy gems are actually relatively simple to use.

传播"消息的技巧是使用其中一种宝石(AncestryClosure_Tree),因为它们为您提供了方法",您可以在其上调用商品.它们的工作方式是在数据库中创建几列,然后在保存/创建所需对象时填充它们

The trick to "treading" your messages is to use one of these gems (either Ancestry or Closure_Tree), as they provide you with "methods" which you can call on your items. They work by creating several columns in your database, populating them as you save / create the objects you desire

线程"问题是一个大问题,因为如果没有层次结构" gem,您将无法调用所需记录的子"对象,从而防止了线程的发生.这是好的Railscast 关于如何实现它的方法:

The "threading" issue is a big one, as without the "hierarchy" gems, you won't be able to call the "child" objects of the record you want, thus preventing the threading from occurring. Here's a good Railscast on how to achieve it:

技巧是使用递归"

就数据的递归"程度而言,递归是创建不确定"循环的地方.例如,如果您有一个带有子对象的对象,则必须先循环遍历子对象,然后依次遍历这些子对象,直到达到显示所有数据的地步:

Recursion is where you create an "indefinite" loop, so far as how "recursive" the data is. EG if you have an object with children, you'll have to cycle through the children, and then the children of those children, recursively until you reach the point of showing all the data:

递归是以自相似的方式重复项目的过程.为了 例如,当两个镜子的表面与 彼此之间,出现的嵌套图像是无限形式 递归.

Recursion is the process of repeating items in a self-similar way. For instance, when the surfaces of two mirrors are exactly parallel with each other, the nested images that occur are a form of infinite recursion.

因此,这是您的操作方式:

As such, here's how you to it:

  1. 请确保您与正确的父母一起保存对象
  2. 要显示主题"对话,请遍历那些父母
  3. 使用递归遍历他们的孩子
  1. Make sure you save your objects with the correct parents
  2. To display the "threaded" conversation, loop through those parents
  3. Use recursion to loop through their children

我们使用 ancestry gem,它存储的层次结构与closure_tree gem略有不同从那以后我们就发现了(打算很快使用闭包树gem).

We use the ancestry gem, which stores the hierarchy slightly differently to the closure_tree gem we've since discovered (intend to use the closure tree gem soon).

因此,您首先必须自己保存任何层次结构:

You firstly have to therefore save any hierarchy yourself:

这将允许您保存该对象的各种父项".这意味着,当您加载对象并希望在其后代之间循环时,将可以使用祖先对象方法:

This will allow you to save the various "parents" for that object. This means that when you load the object, and wish to cycle through its descendent, you'll be able to use the Ancestry object methods:

这意味着您将可以使用以下内容:

Which means you'll be able to use the following:

#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 %>

这篇关于Rails用户到用户消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆