我试图为表单创建的角色生成统计信息。用户输入名称,种族,类别,对齐方式,以及是否随机生成统计数据,或者优先级(从最高到最低分配值)。表单完美无瑕,因为我可以在视图中看到输出。
我现在要做的是从模型中的/ lib类调用一个方法来生成统计数据;但是,我一直收到以下错误(我无法发布图片):
NoMethodError in CharactersController#create
undefined method `[]' for nil:NilClass
Extracted source (around line #14):
12 before_save do
13 generate_stats
14 self.strength = @character_stats[:strength]
15 self.dexterity = @character_stats[:dexterity]
16 self.constitution = @character_stats[:constitution]
17 self.intelligence = @character_stats[:intelligence]
以下是我的部分代码的副本:
在controllers \ characters_controller.rb
中class CharactersController < ApplicationController
def create
@character = Character.new(character_info_params)
@character.name = params[:character][:name].capitalize
@character.alignment = "#{params[:character][:alignment_lr]} #{params[:character][:alignment_ud]}"
if @character.save
redirect_to @character
else
render 'new'
end
end
private
def character_info_params
params.require(:character).permit(:name, :race, :class_, :alignment)
end
end
在models \ character.rb
中class Character < ActiveRecord::Base
require 'random_stats_generator'
attr_accessor :rand_stat_gen
def generate_stats
if @rand_stat_gen == true
@character_stats_inst = RandomStatGenerator.new
@character_stats = @character_stats_inst.generate
end
end
before_save do
generate_stats
self.strength = @character_stats[:strength]
self.dexterity = @character_stats[:dexterity]
self.constitution = @character_stats[:constitution]
self.intelligence = @character_stats[:intelligence]
self.wisdom = @character_stats[:wisdom]
self.charisma = @character_stats[:charisma]
end
#validation passed this point
end
在initializers \ stat_builders.rb
中require "./lib/random_stat_generator.rb"
在lib / random_stat_generator.rb
中class RandomStatGenerator
def initialize
@strength = :strength
@dexterity = :dexterity
@constitution = :constitution
@intelligence = :intelligence
@wisdom = :wisdom
@charisma = :charisma
@character_stats = HashWithIndifferentAccess.new()
end
def self.generate
roll_stats
end
def roll(stat)
@roll_value_1 = (1 + (rand(6)))
@roll_value_2 = (1 + (rand(6)))
@roll_value_3 = (1 + (rand(6)))
@roll_value_4 = (1 + (rand(6)))
@roll_array = [@roll_value_1,@roll_value_2,@roll_value_3,@roll_value_4]
@roll_array = @roll_array.sort_by {|x| x }
@roll_array = @roll_array.reverse
stat = @roll_array[0] + @roll_array[1] + @roll_array[2]
end
def roll_stats
@strength = roll(@strength)
@dexterity = roll(@dexterity)
@constitution = roll(@constitution)
@intelligence = roll(@intelligence)
@wisdom = roll(@wisdom)
@charisma = roll(@charisma)
@character_stats[:strength] = @strength
@character_stats[:dexterity] = @dexterity
@character_stats[:constitution] = @constitution
@character_stats[:intelligence] = @intelligence
@character_stats[:wisdom] = @wisdom
@character_stats[:charisma] = @charisma
return @character_stats
end
end
对我来说,看起来该方法不会返回任何内容,或者根本没有被调用。
我尝试过很多我在网上遇到过的解决方案,但都没有。可能有些事情从这些解决方案中遗留下来并不合理。我只是刚刚开始使用rails,所以我仍然试图习惯一切。
非常感谢你的帮助。
答案 0 :(得分:1)
我想为您的图书馆建议以下组织
# Use a module at top level
module RandomStatGenerator
STATS = [:strength, :dexterity, :constitution, :intelligence, :wisdom, :charisma]
# Use a class Stats if you need to but I don't see why...
class Stats
def initialize
RandomStatGenerator::STATS.each do |stat|
# Below line will do @stat = :stat
instance_variable_set("@#{stat.to_s}", stat)
@character_stats = HashWithIndifferentAccess.new()
end
def roll_stats
@character_stats = RandomStatGenerator.roll_stats
end
end
module_function
# below lines will be considered as module functions
# => call RandomStatGenerator.function_name
def roll
roll_value_1 = (1 + (rand(6)))
roll_value_2 = (1 + (rand(6)))
roll_value_3 = (1 + (rand(6)))
roll_value_4 = (1 + (rand(6)))
roll_array = [roll_value_1,roll_value_2,roll_value_3,roll_value_4]
roll_array = roll_array.sort_by {|x| x }
roll_array = roll_array.reverse
roll_array[0] + roll_array[1] + roll_array[2]
end
def roll_stats
character_stats = {}
STATS.each do |stat|
character_stats[stat] = RandomStatGenerator.roll
end
return character_stats
end
end
然后在你的character.rb
def generate_stats
@character_stats = RandomStatGenerator.roll_stats
end
答案 1 :(得分:1)
Ruby拥有非常强大的功能来处理哈希和数组。 输入重复的作业,例如:
self.strength = @character_stats[:strength]
self.dexterity = @character_stats[:dexterity]
self.constitution = @character_stats[:constitution]
非常沉闷。因此,我们可以简单地重写方法来传递哈希值。
class RandomStatGenerator
# This is just a constant containing all the stats we want to generate.
STATS = [:strength, :dexterity, :constitution, :intelligence, :wisdom, :charisma]
# Create a hash with random roll values for each stat
def self.roll_stats
# This is kind of scary looking but actually just creates an
# hash from an array of keys
Hash[STATS.map {|k| [k, self.roll ] } ]
end
private
def self.roll
# Create an array with 4 elements (nil)
ary = Array.new(4)
# We then replace the nil value with a random value 1-6
ary = ary.map do
(1 + (rand(6)))
end
# sort it and drop the lowest roll. return the sum of all rolls.
ary.sort.drop(1).sum
# a ruby ninja writes it like this
Array.new(4).map { 1 + rand(6) }.sort.drop(1).sum
end
end
输出:
irb(main):032:0> RandomStatGenerator.roll_stats
=> {:strength=>14, :dexterity=>14, :constitution=>14, :intelligence=>13, :wisdom=>10, :charisma=>9}
但是如果你不打算真正创建一个类的实例,那么你应该使用一个模块。
可以使用哈希创建Rails模型,也可以使用哈希值替换其值:
Character.new(RandomStatGenerator.roll_stats)
@character.assign_attributes(RandomStatGenerator.roll_stats)
因此我们可以在Character#generate_stats
中使用它:
def generate_stats
assign_attributes(RandomStatGenerator.roll_stats)
end
你应该使用具有极端偏见的ActiveModel回调。在您的应用程序中以及何时在模型生命周期中进行规范通常是一项挑战。由于before_save
在验证后运行,因此任何验证(例如validates_presence_of :constitution
)都将失败。
在您的情况下,最好在控制器中执行此操作或使用:
before_validation :generate_stats, if: -> { new_record? && @rand_stat_gen }