How to render json using :includes in it? - ruby-on-rails

I've models GuestOrder, OrderBatch, OrderItem
# == Schema Information
#
# Table name: guest_orders
#
# id :integer not null, primary key
# notes :string(255)
# adults :integer
# children :integer
# created :datetime
# placed :datetime
# billed :datetime
# created_at :datetime
# updated_at :datetime
#
class GuestOrder < ActiveRecord::Base
has_many :order_batches, :dependent => :destroy
end
# == Schema Information
#
# Table name: order_batches
#
# id :integer not null, primary key
# placed :datetime
# guest_order_id :integer
# created_at :datetime
# updated_at :datetime
#
class OrderBatch < ActiveRecord::Base
belongs_to :guest_order
has_many :order_items, :dependent => :destroy
end
# == Schema Information
#
# Table name: order_items
#
# id :integer not null, primary key
# quantity :integer
# accepted :datetime
# cooking :datetime
# ready :datetime
# delivered :datetime
# cancelled :datetime
# order_batch_id :integer
# dish_id :integer
# created_at :datetime
# updated_at :datetime
#
class OrderItem < ActiveRecord::Base
belongs_to :order_batch
belongs_to :dish
end
I'm trying to render json in the following method to get a guest_order and its belonging order_batches and order_items by passing guest_order id as parameter.
def getOrderDetails
#To get the details of a particular guest_order and its batches and items
#guest_order = GuestOrder.find_by_id(params[:id])
render :json => #guest_order.to_json(:except => [:created_at, :updated_at],
:includes => {:order_batches => {:except => [:guest_order_id, :created_at, :updated_at],
:includes => {:order_items => {:except => [:order_batch_id, :created_at, :updated_at] } } } } )
end
But I didn't get the expected result, only the details from the guest_orders table is rendered. How to solve this?

I use :include rather than :includes, not sure if that's significant.
Try using the :include without the :except first, and when you get that working, add in the :except.

Related

RoR How to properly set fields_for?

I've got this whole surveys thing:
Survey.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: surveys
#
# id :bigint not null, primary key
# description :string
# hidden :boolean default(FALSE)
# internal_description :string
# internal_name :string
# min_green :integer
# min_orange :integer
# min_red :integer
# required :boolean default(FALSE)
# survey_type :integer default("medical")
# title :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Survey < ApplicationRecord
has_many :questions, class_name: 'Question', dependent: :destroy
has_many :filled_surveys
has_many :study_surveys
has_many :studies, through: :study_surveys
accepts_nested_attributes_for :questions
enum survey_type: %i[medical law]
validates :title, :description, :internal_name, :internal_description, presence: true
end
filled_survey.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: filled_surveys
#
# id :bigint not null, primary key
# score :integer
# state :integer default("pending")
# created_at :datetime not null
# updated_at :datetime not null
# survey_id :bigint not null
# user_id :bigint not null
#
# Indexes
#
# index_filled_surveys_on_survey_id (survey_id)
# index_filled_surveys_on_user_id (user_id)
#
# Foreign Keys
#
# fk_rails_... (survey_id => surveys.id)
# fk_rails_... (user_id => users.id)
#
class FilledSurvey < ApplicationRecord
belongs_to :survey
has_many :questions, through: :survey
belongs_to :user, class_name: 'User'
has_many :answers, class_name: 'Answer'
accepts_nested_attributes_for :answers
has_one :study, through: :survey
enum state: %i[pending done redo]
end
question.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: questions
#
# id :bigint not null, primary key
# description :string
# max :integer
# min :integer
# order :integer default(0)
# placeholder :string
# question_type :integer
# title :string
# created_at :datetime not null
# updated_at :datetime not null
# survey_id :bigint not null
#
# Indexes
#
# index_questions_on_survey_id (survey_id)
#
# Foreign Keys
#
# fk_rails_... (survey_id => surveys.id)
#
class Question < ApplicationRecord
belongs_to :survey
has_many :question_options, class_name: 'QuestionOption', dependent: :destroy
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :question_options, allow_destroy: true, reject_if: proc { |att| att['name'].blank? }
enum question_type: %i[short long number single multiple date]
validates :title, presence: true, on: :create
end
question_option.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: question_options
#
# id :bigint not null, primary key
# display :string
# name :string
# score :integer default(0)
# created_at :datetime not null
# updated_at :datetime not null
# question_id :bigint not null
#
# Indexes
#
# index_question_options_on_question_id (question_id)
#
# Foreign Keys
#
# fk_rails_... (question_id => questions.id)
#
class QuestionOption < ApplicationRecord
belongs_to :question, optional: true
validates :name, :display, :score, presence: true
end
answer.rb
# frozen_string_literal: true
# == Schema Information
#
# Table name: answers
#
# id :bigint not null, primary key
# content :string
# created_at :datetime not null
# updated_at :datetime not null
# filled_survey_id :bigint not null
# option_id :bigint
# question_id :bigint not null
#
# Indexes
#
# index_answers_on_filled_survey_id (filled_survey_id)
# index_answers_on_option_id (option_id)
# index_answers_on_question_id (question_id)
#
# Foreign Keys
#
# fk_rails_... (filled_survey_id => filled_surveys.id)
# fk_rails_... (question_id => questions.id)
#
class Answer < ApplicationRecord
belongs_to :filled_survey
belongs_to :question
belongs_to :option, class_name: 'QuestionOption', optional: true
validates :content, presence: true, length: { minimum: 1 }, on: :update
validate :content, :validate_question_rules, on: :update
end
And view:
/ Body
.w-full.flex-grow.overflow-y-auto
/ Surveys questions forms
= form_for #selected, url: update_filled_survey_path(#selected.id), html: { data: { 'participant-target' => "#{#selected.id}_form" } } do |form|
= form.hidden_field :survey_id
- #selected.questions.includes(:question_options).each do |question|
.rounded-md.bg-gray-100.opacity-75.flex.items-center.justify-between.mb-2.p-2.relative
%span.flex-grow
= render "components/inputs/#{question.question_type}", question: question, form: form
.flex.justify-center.bg-gray-100.rounded-md.cursor-pointer.my-3
%button.w-full.px-6.py-2.bg-green-200.rounded-md.cursor-pointer.hover:bg-green-300{'data-action' => 'click->participant#updateSurvey', 'data-filled' => #selected.id } #{t('views.participant_portal.surveys.complete')}
Partial(for single type question):
.input_group.flex.flex-col.justify-start
%label.text-gray-700.text-md.font-bold
= question.title
- if question.description
%label.text-gray-600.text-sm #{question.description}
.p-4
= form.fields_for question.question_options do |question_form|
= question_form.collection_select(:option_id, question.question_options, :id, :display, { selected: question.question_options.option_id, include_blank: false }, { id: question.id, name: "#{question.id}_answer", class: 'bg-transparent mx-2'})
JS controller (stimulus JS):
updateSurvey (e) {
document.getElementsByTagName('form')[0].submit()
}
Controller
before_action :set_filled, only: %i[fill_survey]
def set_filled
if current_user.profile.active_study && current_user.profile.paid?
#surveys = current_user.profile.active_study.surveys.select(&:medical).map do |survey|
FilledSurvey.includes.find_or_create_by(survey: survey, user: current_user)
end.reject(&:done?)
elsif current_user.profile.active_study && current_user.profile.approved?
#surveys = current_user.profile.active_study.surveys.select(&:medical?).map do |survey|
FilledSurvey.find_or_create_by(survey: survey, user_id: current_user.id,
created_at: FilledSurvey.this_month)
end.reject(&:done?)
elsif action_name == 'law_quiz'
#surveys = current_user.profile.active_study.surveys.select(&:law?).map do |survey|
FilledSurvey.find_or_create_by(survey: survey, user_id: current_user.id,
created_at: FilledSurvey.this_month)
end.reject(&:done?)
end
end
def fill_survey
set_meta_tags(title: t('page_title.participant_portal.fill_survey'))
aasm_state = current_user.profile.aasm_state
redirect_to authenticated_root_path unless %w[paid approved].include?(aasm_state) &&
!#surveys.empty?
#active_study = current_user.profile.active_study
#selected = params[:id] ? FilledSurvey.find(params[:id]) : #surveys.first
# #answers = #selected.survey.questions.map do |question|
# Answer.find_or_create_by(question_id: question.id, filled_survey_id: #selected.id)
# end
# #answers.sort_by { |answer| answer.question.order }
end
What I wanted to do:
Submit all forms with one button
Get ID of QuestionOption that I select for each question
Create Answer for each Question based on QuestionOption
What I get:
"undefined method `option_id' for #<ActiveRecord::Associations::CollectionProxy [#<QuestionOption id: 328, name:(...)"
Can someone explain how to make it works? I want to understand what's wrong with this code, so I can implement this right way

How do I elegantly handle two-sided relations with Rails translations?

I have a family_tree and someone can add their relatives to the tree.
So what happens is there is a membership record created for each family_tree entry.
However, if a Son adds a Dad, we should be able to update the family tree of the Dad to add the "Son" to the tree in the view. What's the best Rails way to approach this? I know Rails does a lot of translations natively, and pluralizations, etc. Anyway for me to leverage that for what I want to do?
Also, what is the class/module that handles that stuff again? ActiveSupport?
This is my User model:
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# created_at :datetime
# updated_at :datetime
# name :string(255)
# confirmation_token :string(255)
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
# invitation_relation :string(255)
# avatar :string(255)
#
class User < ActiveRecord::Base
has_one :family_tree, dependent: :destroy
has_many :memberships, dependent: :destroy
has_many :nodes, dependent: :destroy
has_many :participants, dependent: :destroy
end
FamilyTree.rb
# == Schema Information
#
# Table name: family_trees
#
# id :integer not null, primary key
# name :string(255)
# user_id :integer
# created_at :datetime
# updated_at :datetime
#
class FamilyTree < ActiveRecord::Base
belongs_to :user
has_many :memberships, dependent: :destroy
has_many :members, through: :memberships, source: :user, dependent: :destroy
has_many :nodes, dependent: :destroy
end
Membership.rb:
# == Schema Information
#
# Table name: memberships
#
# id :integer not null, primary key
# family_tree_id :integer
# user_id :integer
# created_at :datetime
# updated_at :datetime
# relation :string(255)
#
class Membership < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
end
Node.rb
# == Schema Information
#
# Table name: nodes
#
# id :integer not null, primary key
# name :string(255)
# family_tree_id :integer
# user_id :integer
# media_id :integer
# media_type :string(255)
# created_at :datetime
# updated_at :datetime
# circa :datetime
# is_comment :boolean
#
class Node < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
belongs_to :media, polymorphic: true, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :node_comments, dependent: :destroy
end
My _tree.html.erb looks like this (truncated for brevity):
<li class="tree-item-name">Great Grandparents
<ul>
<li><% if relative.humanize == "Great Grandfather" || relative.humanize == "Great Grandmother" %>
<%= link_to image_tag(membership.user.avatar.url, size: "48x48", :class => "img-circle") , family_tree_path(membership.user.family_tree), :target => '_blank' %>
<%= link_to membership.user.name, family_tree_path(membership.user.family_tree), :target => '_blank'%>
<% else %>
None added yet, add them <%= link_to 'here', "#" , class: 'btn invite popupbox','data-popup' => 'invite_friend' %>
<% end %>
</li>
</ul>
</li>
<li class="tree-item-name">Grandparents
<ul>
<li><% if relative.humanize == "Grandfather" || relative.humanize == "Grandmother" %>
<%= link_to image_tag(membership.user.avatar.url, size: "48x48", :class => "img-circle") , family_tree_path(membership.user.family_tree), :target => '_blank' %>
<%= link_to membership.user.name, family_tree_path(membership.user.family_tree), :target => '_blank' %>
<% else %>
None added yet, add them <%= link_to 'here', "#" , class: 'btn invite popupbox','data-popup' => 'invite_friend' %>
<% end %>
</li>
</ul>
</li>
I would use the same relations you defined in the question, except this part:
class Membership < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user_one, class_name: 'User'
belongs_to :user_two, class_name: 'User' # I actually have no idea how to call them!
belongs_to :relation # to hold values likes 'Son', 'Dad', etc.
# The model Relation would be as simple as a name and internal reference, nothing else.
# (internal_reference is here to solve the translation problems and other stuff you will understand with the following code)
With a callback after_create to reverse the membership created:
def create_reverse_membership
user_one_is_female = user_one.gender == 'female'
user_two_is_female = user_two.gender == 'female'
son_or_daughter = user_one_is_female ? :daughter : :son
father_or_mother = user_two_is_female ? :mother : :father
case relation.internal_reference.to_sym
when :son
relation = Relation.find_by_internal_reference(father_or_mother)
membership = Membership.where(relation_id: relation.id, user_one: user_two.id, user_two: user_one.id).first
if membership.present?
# This means the reverse membership already exists, do not call Membership.create here because it would cause and endless loop with the callback
else
membership = Membership.create(relation_id: relation.id, user_one: user_two, user_two: user_one)
end
when :father
# almost same logic but with `son_or_daughter`
when :mother
else
end
end
English not being my native language, this code probably lacks of consistency (coherence, logic).
Hope this helps!

Can't mass-assign protected attributes: item

I'm using the version of that gem https://github.com/crowdint/acts_as_shopping_cart for rails 3
I did everything with the conventions names. But I'm getting the error Can't mass-assign protected attributes: item
class ShoppingCartsController < ApplicationController
before_filter :extract_shopping_cart
def create
#product = Video.find(params[:product_id])
#shopping_cart.add(#product, #product.price) # the error is generated on that line
redirect_to shopping_cart_path
end
My model ShoppingCart:
# == Schema Information
#
# Table name: shopping_carts
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class ShoppingCart < ActiveRecord::Base
acts_as_shopping_cart
attr_accessible :price
#accepts_nested_attributes_for :price
end
My model ShoppingCartItem:
# == Schema Information
#
# Table name: shopping_cart_items
#
# id :integer not null, primary key
# owner_id :integer
# owner_type :string(255)
# quantity :integer
# item_id :integer
# item_type :string(255)
# price :float
# created_at :datetime not null
# updated_at :datetime not null
#
class ShoppingCartItem < ActiveRecord::Base
attr_accessible :owner_id, :owner_type, :quantity, :item_id, :item_type, :price
acts_as_shopping_cart_item
end
Can anyone help me what I am missing here?
hope u are aware that
Rails 3
As of Version 0.2.0 Rails 3 is no longer supported. Please use the 0-1-x branch if you still need to implement this gem in a Rails 3 app
gem 'acts_as_shopping_cart', :github => 'crowdint/acts_as_shopping_cart', :branch => '0-1-x'

SQLite3::SQLException: no such column: [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
undefined method `to_f' for #<ActiveRecord::Relation:0x472d0a0>
I'm trying to make a call tracking application to learn twilio and rails.
Right now, I would like to make a graph that shows a user how many phone calls a particular phone number gets per day.
The schema is user has_many phones has_many calls.
I try to make the graph by creating an instance method that counts the number of phones on a particular day, but when I try executing the code, I get the error :
SQLite3::SQLException: no such column: calls.placed_at: SELECT COUNT(*) FROM "calls" WHERE "calls"."phone_id" = 44 AND ("calls"."placed_at" BETWEEN '2012-09-15 00:00:00.000000' AND '2012-09-15 23:59:59.999999')
I don't quite understand the code I'm using for the instance method, and it's probably calling the wrong column. Your help on this would be greatly appreciated.
Here's the important part of my call model:
def total_on(date)
calls.where(placed_at: date.beginning_of_day..date.end_of_day).count
end
Here's how I'm counting the phone calls in my show view
<%= (1.month.ago.to_date..Date.today).map { |date| #phone.total_on(date).to_f}.inspect %>
Here's how I define the #phone variable
#phone = Phone.find_by_id(params[:id])
Here's my complete phone model (for schema reference)
# == Schema Information
#
# Table name: phones
#
# id :integer not null, primary key
# name :string(255)
# twilio_number :integer
# original_number :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Phone < ActiveRecord::Base
attr_accessible :original_number, :user_id, :name, :twilio_number
belongs_to :user
has_many :calls, dependent: :destroy
validates :name, presence: true
validates :twilio_number, presence: true
validates :original_number, presence: true
validates :user_id, presence: true
default_scope order: 'phones.created_at DESC'
validate :check_phone_limit, :on => :create
def check_phone_limit
if User.find(self.user_id).at_max_phone_limit?
self.errors[:base] << "Cannot add any more phones"
end
end
def original_number=(value)
num = value.to_s.gsub(/[^0-9+]/, "")
write_attribute(:original_number, num.to_i)
end
def total_on(date)
calls.where(placed_at: date.beginning_of_day..date.end_of_day).count
end
end
Here's my complete call model
# == Schema Information
#
# Table name: calls
#
# id :integer not null, primary key
# AccountSid :string(255)
# From :string(255)
# To :string(255)
# CallStatus :string(255)
# ApiVersion :string(255)
# Direction :string(255)
# FromCity :string(255)
# FromState :string(255)
# FromZip :string(255)
# FromCountry :string(255)
# ToCity :string(255)
# ToState :string(255)
# ToZip :string(255)
# ToCountry :string(255)
# CallSid :string(255)
# DialCallSid :string(255)
# DialCallDuration :string(255)
# DialCallStatus :string(255)
# RecordingUrl :string(255)
# phone_id :integer
# DialCallMinutes :integer
# created_at :datetime
# updated_at :datetime
#
class Call < ActiveRecord::Base
attr_accessible :AccountSid, :From, :To, :CallStatus, :ApiVersion, :Direction, :FromCity, :FromState, :FromZip, :FromCountry, :ToCity, :ToState, :ToZip, :ToCountry, :CallSid, :DialCallSid, :DialCallDuration, :DialCallStatus, :RecordingUrl, :DialCallMinutes
belongs_to :phone
def self.create_from_incoming_call(params)
user_phone = Phone.find_by_twilio_number(params['To']) #Finds the phone number in the database based on what phone Twilio is calling
twilio_request_params = {
:CallSid => params['CallSid'],
:AccountSid => params['AccountSid'],
:From => params['From'],
:To => params['To'],
:CallStatus => params['CallStatus'],
:ApiVersion => params['ApiVersion'],
:Direction => params['Direction'],
:FromCity => params['FromCity'],
:FromState => params['FromState'],
:FromZip => params['FromZip'],
:FromCountry => params['FromCountry'],
:ToCity => params['ToCity'],
:ToState => params['ToState'],
:ToZip => params['ToZip'],
:ToCountry => params['ToCountry']
:phone_id => user_phone.phone_id
}
call = Call.new(twilio_request_params)
call.save
return call
end
def Call.update_dial_call(params)
twilio_request_params = {
:DialCallSid => params['DialCallSid'],
:DialCallDuration => params['DialCallDuration'],
:DialCallStatus => params['DialCallStatus'],
:RecordingUrl => params['RecordingUrl'],
:DialCallMinutes => (params['DialCallDuration'].to_f/60.to_f).ceil
}
call = Call.where( :CallSid => params['CallSid'] ).first
call.update_attributes twilio_request_params
call.save
end
end
I've been stuck on this for a while; any help would be greatly appreciated!
Your call model uses the standard rails created_at, yet your query was using placed_at, which doesn't exist.

How do I automatically assign a role to a user when my assignment is related to user model on a has_many through ? Rails 3

What I would like to do is when a user is created, it automatically gives them a role.
The thing is that the role is related to the user via an assignment table and a has_many through association.
The code is as follows:
User model
# == Schema Information
# Schema version: 20110214082231
#
# Table name: users
#
# id :integer not null, primary key
# email :string(255)
# encrypted_password :string(128)
# password_salt :string(255)
# reset_password_token :string(255)
# remember_token :string(255)
# remember_created_at :datetime
# sign_in_count :integer
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# username :string(255)
# f_name :string(255)
# l_name :string(255)
# created_at :datetime
# updated_at :datetime
# invitation_token :string(60)
# invitation_sent_at :datetime
# plan_id :integer
# current_state :string(255)
# confirmation_token :string(255)
# confirmed_at :datetime
# confirmation_sent_at :datetime
#
class User < ActiveRecord::Base
before_create :assign
has_many :assignments
has_many :roles, :through => :assignments
def role_symbols
roles.map do |role|
role.name.underscore.to_sym
end
end
def assign
#assignment.build_role(:user_id => self.id, :role_id => '3')
end
end
Assignments model
# Table name: assignments
#
# id :integer not null, primary key
# user_id :integer
# role_id :integer
# created_at :datetime
# updated_at :datetime
#
class Assignment < ActiveRecord::Base
belongs_to :role
belongs_to :user
end
Role model
# == Schema Information
# Schema version: 20101117094659
#
# Table name: roles
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime
# updated_at :datetime
#
class Role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
Firstly, don't use hard-coded ids to find your roles as they may change.
Secondly, use association builders, or just access the roles association yourself.
Thirdly, follow the rule of "Don't Make Me Think" (DMMT) when naming your methods.
With these three things in mind:
def assign_default_role
self.roles << Role.find_by_name("User")
end

Resources