Rails:如何在调用Model.new?

时间:2015-07-20 22:22:58

标签: ruby-on-rails ruby

我有一个用户模型和一个消息模型。用户has_many消息和消息belongs_to用户。

在users_controller的一个方法中,我从API获取电子邮件数据,使用该数据初始化新消息(使用thisMessage = Message.new(messageId,senderName ...))。在控制器中,我多次执行此操作,并将这些消息存储在名为listOfMessages的Array中。到目前为止,这么好,我可以通过listOfMessages [0] .sender(发送者是消息模型属性)来使用消息的属性。

但是,当我刷新页面时,这些消息不会被保存。如果我在每次初始化一个新文件后尝试使用'thisMessage.save'将消息保存到数据库,我会得到错误“undefined method'[]'为nil:NilClass”。

我也试过'thisMessage.save!',我得到错误“未定义的方法'has_key?'为零:NilClass“

那么我应该如何保存这些消息呢?

消息模型

class Message < ActiveRecord::Base
belongs_to :user

def initialize(inputId, inputSender, inputSenderRealName, inputRecievedAt, inputSubject, inputContent, inputIsRead, inputIsReplied, inputImportanceLevel)
    @emailId = inputId
    @sender = inputSender
    @senderRealName = inputSenderRealName
    @recievedAt = inputRecievedAt
    @subject = inputSubject
    @content = inputContent
    @isRead = inputIsRead
    @isReplied = inputIsReplied
    @importanceLevel = inputImportanceLevel
end

来自users_controller的方法我正在使用

def messageList
    @user = current_user
    if @user.current_message == nil
        @user.current_message = 0
    else

    end



    puts "Need Loading " + @user.needsLoading.to_s
    @listOfMessages = Array.new
    messageIdList = Array.new

    --API stuff removed--

        body1 = singleMessage['bodies'][0]['content']
        senderName = singleMessage['addresses']['from'][0]['email']
        senderActualName = singleMessage['addresses']['from'][0]['name']
        recieveTime = singleMessage['sent_at']
        subjectText = singleMessage['subject']
        isRead = singleMessage['flags']['seen']
        hasReplied =  singleMessage['flags']['answered']


        thisMessage = Message.new(messageId, senderName, senderActualName, recieveTime, subjectText, body1, isRead, hasReplied, 0)

        @listOfMessages << thisMessage
        thisMessage.save
    }

    puts @user.messages.length
    @responseText = response
    puts @user.needsLoading.to_s
    puts @user.current_message
    @user.update_column(:needsLoading, 1)



end

最终目标是能够在其他地方执行“current_user.messages [1] .sender”之类的操作。 谢谢!

1 个答案:

答案 0 :(得分:2)

1。不要覆盖ActiveRecord::Model上的初始化方法。

ActiveRecord模型已经采用了属性哈希:

User.new(name: 'Max', awesome: true)

如果属性存在,则将在模型实例上设置。初始化程序需要做很多工作,你不应该轻易破坏它。

如果您确实需要在初始化程序中执行某些操作,请确保调用super并保持界面与模型所期望的相同。

def initalize(hash = {}, &block)
  super
  # do something custom here
end

但在大多数情况下,您可以使用回调或自定义属性设置器。

2。遵循红宝石惯例。

对于这个问题,Ruby和Rails有很简单和强大的命名约定:

  • CONSTANTS都是上限。 Ruby强制执行此操作。
  • ModuleNameClassName是CamelCase(也是一种常量)。
  • variable_nameattribute_namesnake_case。 Ruby并不关心 - 但社区确实如此。忽视这一点,你永远不能和那些很酷的孩子坐在一起。

3。 .update.assign_attributes

有几种方法可以更改模型实例,但注意更改内存中的模型实例和将更改提交到数据库之间的区别非常重要。

@order = Order.new

# change a single attribute.
@order.total = 999 

# Update multiple attributes at once
@order.assign_attributes(
  total: 669,
  shipping_method: 'FEDEX'
) 

# So far we have only updated the instance in memory.
@order.save # Commit the changes to the database

# We can also update the database straight away.

@order.update_attribute(:total, 999) # one attribute at a time

# or with a hash.
@order.update(
  total: 669,
  shipping_method: 'FEDEX'
) 

# Using related objects works the same:
@order.update(
  customer: @customer
) 

# Note that this will also save the related object to the database.
@order.update(
  customer: Customer.new
) 

4。使用服务对象从API调用创建模型实例。

这限制了外部API与您的应用程序之间的联系点数量。而且它们很容易测试。

# Import a message from SomeApi
class MessageImportService

  def initialize(client = MyApi)
    @client = client
  end

  # @return [Array]
  def call
    data = @client.call_some_api_method || []
    data.map do |raw_msg|
      Message.new(
        body1 : raw_msg['bodies'][0]['content'],
        sender_name : raw_msg['addresses']['from'][0]['email'],
        sender_actual_aame : raw_msg['addresses']['from'][0]['name'],
      ) 
    end
  end
end

您可以从控制器执行以下操作:

@messages = MessageImportService.new.call

https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services