parse-stack `has_many` association use - ruby-on-rails

I am using parse-stack to integrate Rails with a Parse Server. (Rails: 5.2.4.5; Ruby: 2.4.0; parse-stack: 1.8.1.)
I want to define attributes and methods on the Parse::User class, such that a User object has_many departments and a User can find its department as the first Department object in the list returned by user.departments.
Here's the class definition for User:
class Parse::User < Parse::Object # [1]
attr_accessor :current_password, :password_confirmation, :role_display_name
property :role
belongs_to :hospital
has_many :conversations, field: :doctor
has_many :tokens, through: :relation
has_many :departments, through: :relation # [2]
validates :password, length: { is: 8 }
def department
self.departments.first # [3]
end
end
# [1] also tried defining `Doctor` as a subclass of `Parse::User`, or `Parse::Object`
# [2] tried `through: :array` as well
# [3] self.departments[0] gives an error in the console, using either :array or :relation
... but upon loading the parse-console, running Parse.auto_generate_models!, and selecting a doctor, I can't find their department with doc.department:
2.4.0 :003 > doc.department
NoMethodError: undefined method `department' for #<Parse::User:0x0055c07f892ef8>
Did you mean? departments
departments=
What fundamental concepts am I missing or getting wrong?

Related

Rails 4.0.3 - has_many through undefined method 'name' for nil:NilClass - only on production

I have a branch model
class Branch < ActiveRecord::Base
validates :name, presence: true
has_many :company_branches
has_many :companies, -> { uniq }, :through => :company_branches
end
and a company model
class Company < ActiveRecord::Base
has_many :company_branches
has_many :branches, -> { uniq }, :through => :company_branches
end
The company can have many branches through company_branches
class CompanyBranch < ActiveRecord::Base
belongs_to :branch, touch: true
belongs_to :company, touch: true
end
On my local machine everything works fine but when I try to save the form on my production Server I get: NoMethodError (undefined methodname' for nil:NilClass)`
The call in my controller is #company.update_attributes(company_params) - The controller receives the branch_ids as array, like branch_ids => [1, 2, 3]
Interesting part of the controller(It fails at #company.update_attributes(company_params)):
class Admin::CompaniesController < Admin::AdminController
respond_to :html, :json
load_and_authorize_resource
def update
#company = Company.find(params[:id])
#company.update_attributes(company_params)
....
end
private
def company_params
params.require(:company).permit(:id, branch_ids: [])
end
end
To clarify: I tried many things and currently only have one branch on my production server. Even with that one single branch I get the error when I try to save it.
Edit: I posted the full stacktrace here: http://pastebin.com/tw6hjkyF
There is a bug with Active Record, you'll need to Upgrade Rails, or downgrade ruby from 2.2 to 2.1.8 or lower.

wrong number of arguments (2 for 1) when trying to create an object in rails console using Parse_resource

I'm using Parse_resource seen here https://github.com/adelevie/parse_resource and
I'm getting the following error when trying to create an activity object in rails console:
ArgumentError: wrong number of arguments (2 for 1)
from /usr/lib/ruby/gems/1.9.1/bundler/gems/parse_resource->7851169f01ba/lib/base.rb:74:in `belongs_to'
My input is
activity = Activity.create
my activity model is:
## activity.rb
class Activity < ParseResource::Base
belongs_to :fromUser, :class_name => 'User'
belongs_to :toUser, :class_name => 'User'
fields :product, :type
end
My user model is :
## user.rb
class User < ParseUser
has_many :activitys, :inverse_of => :fromUser
has_many :activitys, :inverse_of => :toUser
alias :email :username
end
It must be related to the associative properties of these models.Thanks for the help.
I think it is because of alias method, you missed the ,. Do this
alias :email , :username

Using ActiveRelation with :joins on polymorphic has_one to implicitly create relation

We can use ActiveRelation like this:
MyModel.where(:field => "test").create => #<Message ... field:"test">
But it doesnt work for joins with polymorphic has_one associations:
class RelatedModel < AR::Base
# has :some_field
belongs_to :subject, :polymorphic => true
end
class MyModel < AR::Base
# need some dirty magic here
# to build default related_model with params from active_relation
has_one :related_model, :as => :subject, :dependent => :destroy
end
describe MyModel do
it "should auto-create has_one association with joins" do
test = MyModel.joins(:related_model).where("related_models.subject_type" => "MyModel", "related_models.some_field" => "chachacha").create
test.related_model.should_not be_nil
test.related_model.some_field.should == "chachacha"
test.related_model.subject_type.should == "MyModel"
test.related_model.subject_id.should == test.id
# fails =)
end
end
Is it possible to extract active_relation params, pass them to MyModel for use in before_create and build RelatedModel with them?
Diving into ActiveRecord sources i found that
ActiveRecord::Relation covers 'create' with 'scoping' method.
ActiveRecord::Persistance 'create' calls 'initialize' from ActiveRecord::Core.
ActiveRecord::Core 'initialize' calls 'populate_with_current_scope_attributes'
This method declared in ActiveRecord::Scoping uses 'scope_attributes' declared in ActiveRecord::Scoping::Named.
scope_attributes creating relation 'all' and calls 'scope_for_create' on it.
'ActiveRecord::Relation's 'scope_for_create' uses only 'where_values_hash' from current_scope that does not contain rules like 'related_models.subject_type' (this values are contained in where_clauses). So we need to have simple key-value wheres to be used with 'create' on ActiveRecord::Relation. But ActiveRecord not clever enough to know that 'some_field' in where clause should be used with join table.
I found it can be implemented only by accessing where options with self.class.current_scope.where_clauses in 'before_create' on MyModel, parsing them and setting up attributes.
class MyModel < AR::Base
before_create :create_default_node
def create_default_node
clause = self.class.current_scope.where_clauses.detect{|clause| clause =~ /\`related_models\`.\`some_field\`/}
value = clause.scan(/\=.+\`([[:word:]]+)\`/).flatten.first
self.create_node(:some_field => value)
end
end
But it is so dirty, then i decided to find simpler solution and inverted dependency as described in Railscast Pro #394, moved RelatedModel functionality to MyModel with STI. Actually i needed such complicated relation creation because RelatedModel had some functionality common for all models (acts as tree). I decided to delegate 'ancestors' and 'children' to RelatedModel. Inverting dependency solved this problem.
class MyModel < AR::Base
acts_as_tree
belongs_to :subject, :polymorphic => true
end
class MyModel2 < MyModel
end
class RelatedModel < AR::Base
# has :some_field
has_one :my_model, :as => :subject, :dependent => :destroy
end
MyModel.create{|m| m.subject = RelatedModel.create(:some_field => "chachacha")}
MyModel.ancestors # no need to proxy relations

nested mass assignment with mongoid

with a has_one/belongs_to relationship, i cannot seem to update nested records via mass assignment.
models:
class ProductVariation
include Mongoid::Document
has_one :shipping_profile, :inverse_of => :variation
field :quantity
attr_accessible :shipping_profile_attributes
accepts_nested_attributes_for :shipping_profile
end
class ShippingProfile
include Mongoid::Document
belongs_to :variation, :class_name => "ProductVariation"
field :weight, :type => Float
attr_accessible :weight
end
controller:
#variation = ProductVariation.find(params[:id])
#variation.update_attributes(params[:product_variation])
post request:
Parameters:{
"product_variation"=>{
"quantity"=>"13",
"shipping_profile_attributes"=>{
"weight"=>"66",
"id"=>"4dae758ce1607c1d18000074"
}
},
"id"=>"4dae758ce1607c1d18000073"
}
mongo query:
MONGODB app_development['product_variations'].update({"_id"=>BSON::ObjectId('4dae758ce1607c1d18000073')}, {"$set"=>{"quantity"=>13, "updated_at"=>2011-04-28 06:59:17 UTC}})
and i dont even get a mongo update query if the product_variation doesnt have any changed attributes... what am i missing here?
Working models and a unit test are below to demonstrate that you can update child parameters and save to the database
through the parent as intended via accepts_nested_attributes_for and the autosave: true option for relations.
The Mongoid documentation says that an error will be raised for an attempt to set a protected field via mass assignment,
but this is out of date.
Instead, messages like the following are printed to the log file.
WARNING: Can't mass-assign protected attributes: id
You should carefully look for for these messages in the appropriate log file to diagnose your problem.
This will help you notice that you have a nested id field for the shipping profile in your parameters,
and this seems to cause the weight to be rejected as well, probably along with all child parameters.
After adding "attr_accessible :id" to the ShippingProfile model, the weight now gets assigned.
You also need to add "attr_accessible :quantity" (and I've added :id for the unit test) to the ProductVariation model
The next issue is that you need "autosave: true" appended to the has_one relation
in order to have the child updated through the parent,
otherwise you will have to save the child manually.
You might also be interested in sanitize_for_mass_assignment, which can be used to launder out ids.
include ActiveModel::MassAssignmentSecurity
p sanitize_for_mass_assignment(params['product_variation'], :default)
The unit test should make the whole subject clear, I'll leave the controller work to you.
Hope that this is clear and that it helps.
class ProductVariation
include Mongoid::Document
has_one :shipping_profile, :inverse_of => :variation, autosave: true
field :quantity
accepts_nested_attributes_for :shipping_profile
attr_accessible :id
attr_accessible :quantity
attr_accessible :shipping_profile_attributes
end
class ShippingProfile
include Mongoid::Document
belongs_to :variation, :class_name => "ProductVariation"
field :weight, :type => Float
attr_accessible :id
attr_accessible :weight
end
test/unit/product_varitation_test.rb
require 'test_helper'
class ProductVariationTest < ActiveSupport::TestCase
def setup
ProductVariation.delete_all
ShippingProfile.delete_all
end
test "mass assignment" do
params = {
"product_variation"=>{
"quantity"=>"13",
"shipping_profile_attributes"=>{
"weight"=>"66",
"id"=>"4dae758ce1607c1d18000074"
}
},
"id"=>"4dae758ce1607c1d18000073"
}
product_variation_id = params['id']
shipping_profile_id = params['product_variation']['shipping_profile_attributes']['id']
product_variation = ProductVariation.create("id" => product_variation_id)
shipping_profile = ShippingProfile.create("id" => shipping_profile_id)
product_variation.shipping_profile = shipping_profile
assert_equal(1, ProductVariation.count)
assert_equal(1, ShippingProfile.count)
product_variation.update_attributes(params['product_variation'])
assert_equal('13', ProductVariation.find(product_variation_id)['quantity'])
assert_equal(66.0, ShippingProfile.find(shipping_profile_id)['weight'])
p ProductVariation.find(product_variation_id)
p ShippingProfile.find(shipping_profile_id)
end
end
test output
Run options: --name=test_mass_assignment
# Running tests:
#<ProductVariation _id: 4dae758ce1607c1d18000073, _type: nil, quantity: "13">
#<ShippingProfile _id: 4dae758ce1607c1d18000074, _type: nil, variation_id: BSON::ObjectId('4dae758ce1607c1d18000073'), weight: 66.0>
.
Finished tests in 0.014682s, 68.1106 tests/s, 272.4424 assertions/s.
1 tests, 4 assertions, 0 failures, 0 errors, 0 skips
Process finished with exit code 0

undefined method when trying to access related records in model rails 3

What's wrong in my model, using rails 3.0.5 and ruby 1.9.2?
class Milestone < ActiveRecord::Base
has_many :capstone_milestones
has_many :capstones, :through => :capstone_milestones
belongs_to :department
attr_accessible :id, :name, :description, :department_id, :project
accepts_nested_attributes_for :capstone_milestones, :allow_destroy => true
def before_create # or after_initialize
self.project ||= 'Default'
end
def xpos
(Milestone.department.id - 100000)*100
end
end
When i do milestone.xpos in the view, i get "undefined method `department'" error message.
Thx!
You cant access department by class name because you will get it as an instance method.
You can access like
#milestone = Milestone.find(id)
#milestone.department_id
In your case just replace Milestone with self.
(self.department.id - 100000)*100

Resources