What's wrong with this loop? - ruby-on-rails

class GameController < ApplicationController
def index
#games = Game.all
respond_to do |format|
format.html
end
end
def start_game
session[:round] ||= 1
session[:points] ||= 0
#round = session[:round]
#points = session[:points]
end
def next_round
session[:round] += 1
session[:points] += 1200
#round = session[:round]
#points = session[:points]
end
def generate_round
numbers = Array.new(6){rand(9)}
#addition = []
#display = numbers
numbers.inject do |s, i|
#addition << s + i
#addition.last
end
end
def new
if #round == nil
start_game
generate_round
else
generate_round
end
if session[:addition]
if not session[:addition].index(params[:guess].to_i).nil?
puts "Correct."
next_round
else
puts 'Game over.'
end
end
session[:addition] = #addition
respond_to do |format|
format.html
end
end
end
Hey guys,
I`m trying to put together this mini game in ruby that depends on guessing numbers.
After every guess points are added and the level is increased by one.
However with the current code, I`m getting stuck at round 2.
Most likely something is resetting those variables for some reason but I can seem to pin point what it is.
Would be grateful for any kind of help.
::Edit::
Code updated. Problem solved!
Thanks for the help #blackbird07, #robertodecurnex and #fl00r!

Controller is stateless so of course all variables are reseted each time you call it.
You should use some datastorage (database, filesystem) to store your current state.
And another your problem is that all this code shouldn't belong to controller at all.

You do not increase the counters for session[:round] and session[:points] in your next_round action. Do this and it should work.
session[:round] += 1
session[:points] += 1200
#round = session[:round]
#points = session[:points]

Since you are keeping the round on the session you should use the session value instead of the instance variable or at least create a filter to set this variable on every request.
Using the filter:
before_filter :set_round
private
def set_round
#round = session[:round]
end
The new method (action) is making the following:
if #round = 0 then
It's assigning 0 to #round instead of compare it.
Try if #round == 0 or just if #round.zero?
You will need also to increase the session value and not just the #round variable one.
Remember:
= #=> Assignation
== #=> Equality, usually overwritten by the classes to return true base on the equality of the state/attributes of two objects.
=== #=> Equality, usually defined to compare the identity of two objects (to return true only if both objects are actually the same object).

Related

How does recalling a variable work in a method?

I have the following method:
vendor_orders = VendorOrder.where(id: params[:vendor_order_ids])
orders = Order.find(vendor_orders.pluck(:order_id))
products = Product.joins(:vendor_product).where(vendor_products:{vendor_id: current_user.id }).ids #get all vendor_products that match current_user.vendor
line_items = LineItem.joins(:shop_product).where(cart_id: orders.pluck(:cart_id), fulfillment_status: "processing", shop_products: {product_id: products}).where.not(fulfillment_status: "canceled")
messages = []
n = 0
puts "line items: #{line_items.count}" #puts out 1
line_items.map do |li|
if li.update_attribute(:fulfillment_status, params[:mass][:fulfillment_status])
n+=1
else
messages << "#{vendor_order.vendor_order_token}"
end
end
puts "line items2: #{line_items.count}" #puts out 0
if n == line_items.count
flash.keep[:notice] = "Update for #{vendor_orders.count} order(s) and #{n} product(s) successful"
else
flash.keep[:notice] = "Failed update for Order: #{messages.join if messages.any?}"
end
puts "line item3 #{line_items.count}" #puts out 0
respond_to do |format|
format.html { redirect_to vendor_orders_path }
end
The question i have is about the puts
When calling line_items.count after I update the line_items to then not match the variable, does it recall line_items from above?
Is this true? I always assumed once something was defined and passed, it would stay at the rate, unless redefined.
Marek solved the issue by letting me know .count is a call to the database which will then call what you defined previously.
To solve this, I just use line_items_count = line_items.count and use that above any alterations to check against it.

Adding a counter to controller. Rails 4

I have a rails 4 app. In the controller, I iterate through each assignment entry in the database to check if a requirement is associated with more than one assignment. However, I can't figure out how to add a counter, i.e. hit = 0, hit = 1, etc. to the controller.
EDIT: The relationship between assignment and requirement is HABTM.
My code is below:
def check_requirements
#assignments = Assignment.all
#assignment = Assignment.find(params[:id])
#requirement = Requirement.find(params[:requirement_id])
#assignments.each do |assignment|
if assignment.include(requirement)
#here's where the counter should go
end
end
if counter is greater than zero or one, do nothing
else #assignment.delete(requirement)
end
You can use Enumerable#each_with_index
def check_requirements
#assignments = Assignment.all
#assignment = Assignment.find(params[:id])
#requirement = Requirement.find(params[:requirement_id])
#assignments.each_with_index do |assignment,hit|
if assignment.include(requirement)
p "hit : #{hit}"
end
end
if counter is greater than zero or one, do nothing
else #assignment.delete(requirement)
end
def check_requirements
#assignments = Assignment.all
#assignment = Assignment.find(params[:id])
#requirement = Requirement.find(params[:requirement_id])
counter = 0
#assignments.each do |assignment|
if assignment.include(requirement)
counter+=1
end
end
if counter is greater than zero or one, do nothing
else #assignment.delete(requirement)
end

undefined method `<<' for #<Answer::ActiveRecord_Relation:0x007fada31c7430>

Hi I create a controller Game to display a Q/A game
And I am blocked with <<, here is the code
def play
lvlup(lvl)
if lvl == 1
set_questions
else
get_questions
end
#answers = Answer.where.not(id: question.answer_id).limit(2).order("RANDOM()")
#answer ||= []
#answers << question.answer
#answers = #answers.shuffle
render 'play'
end
I create an array and I put the related answer in the global answers I want to display 4 Max.
Why does the undefined is here?
Here is the total code
class GamesController < ApplicationController
attr_accessor :lvl
def welcome
end
def congrat
end
def play
lvlup(lvl)
if lvl == 1
set_questions
else
get_questions
end
#answers = Answer.where.not(id: question.answer_id).limit(2).order("RANDOM()")
#answer ||= []
#answers << question.answer
#answers = #answers.shuffle
render 'play'
end
def loose
#question = Question.find(params[:question])
flash.now[:alert] = "Miss..."
render 'loose'
end
def check
#lvl = params[:lvl].to_i
answer_id = params[:id].to_i
question = Question.find(params[:question])
if #lvl == lvlmax
render action: 'congrat' and return
elsif answer_id == question.answer_id
flash.now[:notice] = "Well done !"
play
else answer_id != question.answer_id
loose
end
end
private
def lvlup(value)
#lvl = 1 + value.to_i
end
def lvlmax
#lvlmax = Question.all.count
end
def set_questions
#questionsids = []
Question.all.shuffle.each do |d|
#questionsids << d.id
end
cookies[:questions] = #questionsids
end
def get_questions
#questions = cookies[:questions].split('&')
end
def questions
#questions = cookies[:questions]
end
def question
#question = Question.find(questions[lvl])
end
end
Thank you for your help.
You are trying to append to the #answers result - this is an ActiveRecord relation, you cannot append data to that array.
Add .to_a in the end of your line where you set #answers to allow you to append to the array.
#answers = Answer.where.not(id: question.answer_id).limit(2).order("RANDOM()").to_a
mtrolle's answer might be correct, but I have my doubts as to why ActiveRecord::Relation was not returned as Array by default. (Also as mentioned by BroiStatse in his comment.)
I too noticed the same problem with my local setup however it was attributed to another issue all together. I am sharing this here in case you too happen to use MySQL.
Answer.where.not(id: question.answer_id).limit(2).order("RANDOM()")
returns an ActiveRecord::Relation object. And it translates to following SQL:
SELECT `answers`.* FROM `answers` WHERE (id != ID) ORDER BY RANDOM() LIMIT 2
When I try running the same in MySQL, I get:
ERROR 1305 (42000): FUNCTION database.RANDOM does not exist
Apparently MySQL does not have RANDOM() function, instead it uses RAND().
Converting ActiveRecord query accordingly returned correct Array to me:
Answer.where.not(id: question.answer_id).limit(2).order("RAND()")

One method for two models. How to pass name of model as variable to controller?

I have two methods in two different controllers (Posts & Boards). They are almost same. The difference is only model-instance-association name. To DRY this I think to write the method in module, but how to share it between Post and Board?
def init_post_comments
#user = current_user
a = #user.posts.pluck(:id) # not very nice...
b=params[:post_ids] ||= []
b = b.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # checkbox just checked
#post = Post.find_by_id(id)
if #post.users.empty?
#post.update_attribute(:new_follow, true)
end
#user.posts << #post
end
unfollow.each do |id| # if checkbox was unchecked
#post = Post.find_by_id(id)
remove_post_from_user(#post)# here we destroy association
end
if follow.size > 0
get_post_comments_data
end
redirect_to :back
end
UPDATE Ok, if I'll move the methods to model's concern how I should work with associations here? Here #user.posts.pluck(:id) and here #user.boards.pluck(:id) with what I can replace posts and boards so it can work with both of them?
So, I did it! I don't know if it's right way, but I DRY this code.
Two controllers:
posts_controller.rb
def init_comments
if Post.comments_manipulator(current_user, params[:post_ids] ||= []) > 0
#posts = Post.new_post_to_follow
code = []
#posts.each do |post|
group = post.group
code = code_constructor('API.call')
end
Post.comments_init(get_request(code), #posts)
end
redirect_to :back
end
boards_controller.rb
def init_comments
if Board.comments_manipulator(current_user, params[:board_ids] ||= []) > 0
#boards = Board.new_board_to_follow
code = []
#boards.each do |board|# подготовка запроса
group = board.group
code = code_constructor('API.call')
end
Board.comments_init(get_request(code), #boards)
end
redirect_to :back
end
As you can see they are absolutely same.
In models board.rb and post.rb - include CommentsInitializer
And in models\concerns
module CommentsInitializer
extend ActiveSupport::Concern
module ClassMethods
def comments_manipulator(user, ids)
relationship = self.name.downcase + 's'
a = user.send(relationship).pluck(:id)
b = ids.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # start to follow newly checked obj
#obj = self.find_by_id(id)
if #obj.users.empty?
#obj.update_attribute(:new_follow, true)
end
user.send(relationship) << #obj
end
unfollow.each do |id| # remove from following
#obj = self.find_by_id(id)
remove_assoc_from_user(#obj, user)#destroy relation with current user
end
follow.size
end
def comments_init(comments, objs)
i = 0
objs.each do |obj| # updating comments data
if comments[i]['count'] == 0
obj.update(new_follow: false)
else
obj.update(new_follow: false, last_comment_id: comments[i]['items'][0]['id'])
end
i += 1
end
end
def remove_assoc_from_user(obj, user)
user = user.id
if user
obj.users.delete(user)
end
end
end
My code works. If you know how to make it better please answer!

NoMethodError undefined method

Working on final class project. I need to calculate the GPA of my major credits and non major credits separately for a transcript page. When I run this code below as a controller it works fine and show my total credit hours for major and non major but when I put this code
#GPA_for_major = (course.credits * course.grade.scale) / course.credits
in the If statement I get NoMethodError in TransController#transcript
undefined method 'credits' for # Course::ActiveRecord_Relation:0x00000007b99798>
class Transcript
def initialize (course_array)
#course = course_array
#total_non_major_credits = 0
#total_major_credits = 0
#GPA_for_major = 0
#GPA_for_non_major = 0
for item in #course
if item.is_for_major
#total_major_credits = #total_major_credits + item.credits
else
#total_non_major_credits = #total_non_major_credits + item.credits
end
end
end
def course
#course
end
def total_non_major_credits
#total_non_major_credits
end
def total_major_credits
#total_major_credits
end
def GPA_for_major
#GPA_for_major
end
def GPA_for_non_major
#GPA_for_non_major
end
end
This is the Controller for my transcript page
class TransController < ApplicationController
def transcript
#courses = Course.all
#transcript =Transcript.new(#courses)
end
end
I'm not sure what else to include because this is my first post but any help will be awesome! Thanks!
#course appears to refer to an array of courses and the if statement is within a loop that iterates over the items setting a local variable item for each course. Given that, you should use item instead of course:
#GPA_for_major = (item.credits * item.grade.scale) / item.credits

Resources