I am currently working on a scoring system for my game application and for some reason points are not adding up. The goal is whenever the player guesses the correct answer, points are added. For each new player, the score is set to 0.
question#validate_answer:
def validate_answer
#correct_answer = Answer.where(correct: true).map(&:text)
#selected_answer = params[:answer]
#player_score = Player.where(id: params[:id]).map(&:score)
if #correct_answer.include? (#selected_answer)
#player_score[0] += 1
render :success
else
render :error
end
end
Quesiton.rb
class Question < ActiveRecord::Base
belongs_to :category
has_many :answers
has_one :video_clue
has_many :answers
def correct_answer
answers.find_by correct: true
end
end
Answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
end
Player.rb
class Player < ActiveRecord::Base
has_secure_password
def admin?
self.admin == 'admin'
end
end
Schema Tables for Answers and Players
create_table "answers", force: :cascade do |t|
t.integer "question_id"
t.string "text"
t.boolean "correct"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "answers", ["question_id"], name: "index_answers_on_question_id", using: :btree
create_table "players", force: :cascade do |t|
t.string "user_name"
t.string "password_digest"
t.integer "score"
t.string "role"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I would restructure the code the like this:
def validate_answer
#question = Question.find(params[:q_id])
#correct_answer = Answer.find_by_question_id(params[:q_id]).text.downcase
#selected_answer = params[:answer].downcase
#player = Player.find(params[:id])
if #selected_answer == #correct_answer
#player.increment!(:score)
render :success
else
render :error
end
end
increment! automatically pings the #player object for the column specified. It saved the trouble of trying to convert it to an array and access the index which was sort of roundabout.
NOTE: Edited Answer per chat conversation.
just see how less lines of code are need to be done for that
def validate_answer
#i think this is a bad approach to compare the text of the answer
#with the text of the given answer
#the better one would be to assing UUID to the answer or just use the regular ID
# something like this params[:answer][:uuid]
# or params[:answer][:id]
# we need to find the answer related to the question, otherwise we
# could throw in just random IDs and they are still saying "correct"
given_answer = Questions.find(params[:question_id]).answers.find params[:answer][:id]
# if we use UUID we dont need to give the question id, since then the ID can't be guessed
if given_answer.correct?
# current_user is a player.
# current_user is a method from devise (u should use devise)
current_user.award_points! given_answer
render :success
else
ender :error
end
end
class Player
def award_points! answer
# adding the points to the user
# and save it
current_user.award_points += answer.points
current_user.save
#better approach would be to save the question which was answered for the user
# like has_many :answered_questions
# so then u could also track which questions already been answered by the user and not awarding him twice
end
end
Related
Im very new tor ails and still learning. My project that I am working on is set up for a user to have many cars and cars belong to a user.
class User < ApplicationRecord
validates :name, presence: true, uniqueness: true
has_secure_password
has_many :cars
end
class Car < ApplicationRecord
belongs_to :user
end
My flow is set up to where after a user signs in they can create their vehicle. However I am having trouble creating the car so that it will attach to the user and I am getting an error each time I try different methods.
def create
#car = Car.new(car_params)
#user = User.find(params[:id])
#car.save
redirect_to user_path
end
private
def car_params
params.require(:car).permit(:user_id, :make, :model, :color)
end
my schema seems to be set up correctly
create_table "cars", force: :cascade do |t|
t.string "make"
t.string "model"
t.string "color"
t.integer "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_cars_on_user_id"
end
But again, I am clearly doing something wrong and I am having trouble finding my answers online.
Well, if you have a login, you probably have a current_user set up. The logged one. Inside your create method on your controller you can set the car information using the logged in user like:
def create
#car = Car.new(car_params)
#car.user_id = current_user.id
#car.save
redirect_to user_path
end
You can also remove the :user_id from the car_params if you have the information about the logged user.
If you don't have the current_user or whatever method to get the logged in user created, you will need to select the user inside the form via a HTML select or something like that, then you can keep the :user_id inside car_params and just remove the line about setting the user_id on #car to save.
I'm new to RoR and I want to create simple page like a task manager (to add and remove tasks) so I created 2 tables with association between them (Track and Item).
Here is 2 models:
class Item < ApplicationRecord
belongs_to :track, optional: :true
end
class Track < ApplicationRecord
has_many :items, dependent: :destroy
end
And I need to set association when I create or delete any track item. But when I create it I just see my track item (with an empty field in associated table)
For example:
rails c
Track.create(item: 'Asafa Pauel', description: 'This is a description') - works fine (added all field to db)
Item.all - track_id field is empty - but it should show id of track item. Why is this?
And my Tracks controller:
class TracksController < ApplicationController
def index
#track = Track.all
end
def show
#track = Track.all
end
def new
#track = Track.new
end
def create
#track = Track.new(track_params)
#item = Item.new(track_id: #track.id)
if #track.save! && #item.save!
flash[:success] = "It works!"
redirect_to tracks_path
else
flash[:success] = "Its wrong!"
end
end
private
def track_params
params.require(:track).permit(:item, :description)
end
end
And Items controller:
class ItemsController < ApplicationController
def create
#item = Item.new(item_params)
end
private
def item_params
params.require(:item).permit(:track_id)
end
end
And db schema:
ActiveRecord::Schema.define(version: 2019_05_23_112947) do
enable_extension "plpgsql"
create_table "items", force: :cascade do |t|
t.bigint "track_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["track_id"], name: "index_items_on_track_id"
end
create_table "tracks", force: :cascade do |t|
t.string "item"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Thanks in advance
Your new 'Track' object doesn't have an ID yet, so you can't assign its value to Item.track_id.
First you'll have to save the Track, then create a new Item.
Also, if you create a new Track from console, you won't trigger your "create" method in the controller: it will be called only if you create a new Track from browser.
If you want to create a new Item every time you create a Track, you'll have to do something like this in your model file "track.rb":
after_save :create_new_item
def create_new_item
self.items.create
end
P.S.: the "track.rb" file is in "app/models" in your Rails application.
Here is my recurring payment model. I want it to optionally belong to each of the included resources, but to allow creation with only one parent resource. I tried setting the default for each foreign key to 0, but I still get an error when I try to create instances saying "bank account must exist", "investment must exist", etc. I am sure there must be a way to accomplish this, but I cannot see how? *Edit: I solved this by defaulting the foreign id's to 1 instead of 0, since this will just be seed data anyway, but I would still love to know if anyone has a better solution!
class RecurringPayment < ApplicationRecord
belongs_to :bank_account
belongs_to :credit_card
belongs_to :investment
belongs_to :loan
def bank_account_name
self.try(:bank_account).try(:name)
end
def bank_account_name=(name)
bank_account = BankAccount.find_by(name: name)
if bank_account
self.bank_account = bank_account
end
end
def credit_card_provider
self.try(:credit_card).try(:provider)
end
def credit_card_provider=(provider)
credit_card = CreditCard.find_by(provider: provider)
if credit_card
self.credit_card = credit_card
end
end
def investment_name
self.try(:investment).try(:name)
end
def investment_name=(name)
investment = Investment.find_by(name: name)
if investment
self.investment = investment
end
end
def loan_name
self.try(:loan).try(:name)
end
def loan_name=(name)
loan = Loan.find_by(name: name)
if loan
self.loan = loan
end
end
end
Here is the schema:
create_table "recurring_payments", force: :cascade do |t|
t.string "source"
t.boolean "status"
t.date "pay_date"
t.integer "pay_amount"
t.integer "duration"
t.integer "bank_account_id", default: 0
t.integer "credit_card_id", default: 0
t.integer "loan_id", default: 0
t.integer "investment_id", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "payment_frequency"
end
In Rails 5, belongs_to associations are required by default.
You can change this behavior in a config file, by adding:
Rails.application.config.active_record.belongs_to_required_by_default = false
Or in a specific class:
class RecurringPayment < ApplicationRecord
belongs_to :bank_account, optional: true
belongs_to :credit_card, optional: true
belongs_to :investment, optional: true
belongs_to :loan, optional: true
end
In your code you should always check before using the association model, as it may not exist.
Check section 4.20 in this documentation: http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html
I'm fairly new to both Ruby and Rails and haven't internalized a lot of it. The problem I'm faced with seems like it should be simple to solve, but alas it is not simple for me. I apologize if some of my terminology is imprecise.
Versions: Rails 4.2.0 | Ruby 2.1
I have models Subject, Post & Synopsis.
Posts are nested under Subject, so when I create a Post I'm able to update the posts table with subject_id like so:
def create
#subject = Subject.find(params[:subject_id])
#post = current_user.posts.build(params.require(:post).permit(:title, :body))
#post.subject = #subject
...
A Summary is nested under and belongs to one Post. When creating a Summary I want to update the posts table with summary_id. I just can't wrap my head around how to do it and haven't been able to find out how either on Stack Overflow or elsewhere.
If it were a SQL command, and the id of the current post was 23 and the id of the current synopsis was 9, it would be something like UPDATE posts SET posts.synopsis_id = 9 WHERE posts.id = 23.
The relevant controller, models and schema info are below. Let me know if I need to provide more information.
Controller:
synopses_controller.rb
def create
#subject = Subject.find(params[:subject_id]) #find the Subject id
#post = Post.find(params[:post_id]) #find the post id
#synopsis = Synopsis.new(params.require(:synopsis).permit(:name, :description))
#UPDATE THE POST WITH SYNOPSIS_ID!
if #synopsis.save
flash[:notice] = "Synopsis was saved."
redirect_to [#subject, #post, #synopsis] #go to the Synopsis page
else
flash[:error] = "There was an error saving the Synopsis. Please try again."
render :show
end
end
Models:
synopsis.rb
class Synopsis < ActiveRecord::Base
belongs_to :post
end
post.rb
class Post < ActiveRecord::Base
has_one :synopsis
has_many :comments
belongs_to :user
belongs_to :subject
end
Schema:
schema.rb
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "subject_id"
t.integer "synopsis_id"
end
create_table "synopses", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
You could do:
def create
# ....
if #synopsis.save
#post.update(:synopsis_id, #synopsis.id)
flash[:notice] = "Synopsis was saved."
redirect_to [#subject, #post, #synopsis] #go to the Synopsis page
else
#....
end
You might be overthinking this. Given your simple sql command you want to do:
UPDATE posts SET posts.synopsis_id = 9 WHERE posts.id = 23
You'd just have to do something like this to accomplish that.
Post.find(23).update(:synopsis_id => 9)
I need some help with polymorphic associations. Below is my structure:
class Category < ActiveRecord::Base
has_ancestry
has_many :categorisations
end
class Categorisation < ActiveRecord::Base
belongs_to :category
belongs_to :categorisable, polymorphic: true
end
class classifiedAd < ActiveRecord::Base
belongs_to :user
has_one :categorisation, as: :categorisable
end
And here is my schema.rb
create_table "classifiedads", force: true do |t|
t.string "title"
t.text "body"
t.decimal "price"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "classifiedads", ["user_id"], name: "index_classifiedads_on_user_id", using: :btree
create_table "categories", force: true do |t|
t.string "name"
t.string "ancestry"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "categories", ["ancestry"], name: "index_categories_on_ancestry", using: :btree
create_table "categorisations", force: true do |t|
t.integer "category_id"
t.integer "categorisable_id"
t.string "categorisable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
It seems like the associations is correct as when I'm in the console I can do the appropriate commands and all seems to return the right results, for example: Category.first.categorisations or ClassifedAd.first.categorisation. But what I don't understand is saving the association from the Create and editing the record via the Update actions. I'm using simple_form to create my forms and when looking at the params I get the below:
{"title"=>"Tiger",
"body"=>"Huge Helicopter",
"price"=>"550.0",
"categorisation"=>"5"}
and this fails to update or even create as I get this error : Categorisation(#70249667986640) expected, got String(#70249634794540) My controller actions code are below:
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
#classified.save
end
def update
#classified.update(classifiedad_params)
end
def classifiedad_params
params.require(:classifiedad).permit(:title, :body, :price)
end
I think it has something to do with the params as categorisation should be within a sub hash of results, is this right? Also, I need to do something extra within the actions, but what? What the params[:categorisation] value needs to do is save the number into the Categorisations.category_id table column and also save the polymorphic association. This table will be used across other models, which will also be a has_one association, as the user will only be able to select one category for each record. I really hope someone can help me here as the more I look into it the more I get confused :S Please let me know if you ned anymore info from me.
I'm using Rails 4 and Ruby 2
EDIT 2
I managed to get something working but I'm still not sure if its right. Below is the update code for the Create and Update actions. Would be good to know if there is a better way of doing this?
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
**** NEW
cat = Categorisation.new(category_id: params[:classified][:categorisation])
#classified.categorisation = cat
**** END NEW
#classified.save
end
def update
**** NEW
#classified.categorisation.update_attribute(:category_id, params[:classified][:categorisation])
**** END NEW
#classified.update(classifiedad_params)
end