1

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
2
  • does one of the answers could help you? Commented Aug 7, 2015 at 11:19
  • I haven't forgot to answer either of these. I'm having some DB issues, in another question. I think your answer is closest to what I'm looking for so I'll mark that for now. Commented Aug 7, 2015 at 17:36

2 Answers 2

0

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.

Sign up to request clarification or add additional context in comments.

1 Comment

If you don't want to save to the database the solution is to use conditional assignment like in Robs answer.
0

you can add a method like

def opinions
  @opinions ||= Hash[ Simulation.keys.map { |key| [key, 0] } 
end

this will cache the operation into the variable @opinions

i would also add a method like

def arrangement
  @arrangement ||= Array.new(y_size) { Array.new(x_size) } 
end

def rand_opinion
  Simulation.keys[rand(0..2)]
end

and then replace the variables with your methods

def generate_arrangement    
  arrangement.each_with_index do |row, y_index|
    row.each_with_index do |current, x_index|
        arrangement[y_index][x_index] = rand_opinion
        opinions[rand_opinion] += 1
    end
  end
end

now your opinions and your arrangement will be cached and the code looks better. you didn't have to add a new column in you table

you now hat to replace the @opinions variable with your opinions method

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.