Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have this variable opinions I want to store as an instance variable in my model... am I right in assuming I will need to add a column for it or else be re-calculating it constantly?

My other question is what is the syntax to store into a column variable instead of just a local one?

Thanks for the help, code below:

# == Schema Information
#
# Table name: simulations
#
#  id          :integer          not null, primary key
#  x_size      :integer
#  y_size      :integer
#  verdict     :string
#  arrangement :string
#  user_id     :integer
#

class Simulation < ActiveRecord::Base
    belongs_to :user

    serialize :arrangement, Array

    validates :user_id, presence: true
    validates :x_size, :y_size, presence: true, :numericality => {:only_integer => true}
    validates_numericality_of :x_size, :y_size, :greater_than => 0

    def self.keys
        [:soft, :hard, :none]
    end 

    def generate_arrangement    
        @opinions = Hash[ Simulation.keys.map { |key| [key, 0] } ]
        @arrangement = Array.new(y_size) { Array.new(x_size) }

        @arrangement.each_with_index do |row, y_index|
            row.each_with_index do |current, x_index|
                rand_opinion = Simulation.keys[rand(0..2)]
                @arrangement[y_index][x_index] = rand_opinion
                @opinions[rand_opinion] += 1
            end
        end
    end

    def verdict
        if @opinions[:hard] > @opinions[:soft]
          :hard
        elsif @opinions[:soft] > @opinions[:hard]
          :soft
        else
          :push
        end
    end 

    def state 
        @arrangement
    end

    def next
        new_arrangement = Array.new(@arrangement.size) { |array| array = Array.new(@arrangement.first.size) }
        @opinions = Hash[ Simulation.keys.map { |key| [key, 0] } ]

        @seating_arrangement.each_with_index do |array, y_index|
            array.each_with_index do |opinion, x_index|
                new_arrangement[y_index][x_index] = update_opinion_for x_index, y_index
                @opinions[new_arrangement[y_index][x_index]] += 1
            end
        end

        @arrangement = new_arrangement
    end

    private 

    def in_array_range?(x, y)
        ((x >= 0) and (y >= 0) and (x < @arrangement[0].size) and (y < @arrangement.size))
    end

    def update_opinion_for(x, y)
        local_opinions = Hash[ Simulation.keys.map { |key| [key, 0] } ]

        for y_pos in (y-1)..(y+1)
            for x_pos in (x-1)..(x+1)
                if in_array_range? x_pos, y_pos and not(x == x_pos and y == y_pos)
                    local_opinions[@arrangement[y_pos][x_pos]] += 1
                end
            end
        end

        opinion = @arrangement[y][x]
        opinionated_neighbours_count = local_opinions[:hard] + local_opinions[:soft]

        if (opinion != :none) and (opinionated_neighbours_count < 2 or opinionated_neighbours_count > 3)
            opinion = :none    
        elsif opinion == :none and opinionated_neighbours_count == 3
            if local_opinions[:hard] > local_opinions[:soft]
                opinion = :hard
            elsif local_opinions[:soft] > local_opinions[:hard]
                opinion = :soft
            end 
        end 

        opinion
    end

end
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
144 views
Welcome To Ask or Share your Answers For Others

1 Answer

ActiveRecord analyzes the database tables and creates setter and getter methods with metaprogramming.

So you would create a database column with a migration:

rails g migration AddOpinionToSimulation opinion:hash

Note that not all databases support storing a hash or a similar key/value data type in a column. Postgres does. If you need to use another database such MySQL you should consider using a relation instead (storing the data in another table).

Then when you access simulation.opinion it will automatically get the database column value (if the record is persisted).

Since ActiveRecord creates a setter and getter you can access your property from within the Model as:

class Simulation < ActiveRecord::Base
  # ...

  def an_example_method
    self.opinions # getter method
    # since self is the implied receiver you can simply do
    opinions
    opinions = {foo: "bar"} # setter method.
  end
end 

The same applies when using the plain ruby attr_accessor, attr_reader and attr_writer macros.

When you assign to an attribute backed by a database column ActiveRecord marks the attribute as dirty and will include it when you save the record.

ActiveRecord has a few methods to directly update attributes: update, update_attributes and update_attribute. There are differences in the call signature and how they handle callbacks.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...