Similar questions have been asked before but I just can't figure this out.
So I have Model_A and Model_B. Model_B belongs_to Model_A. What I want to do is when I create Model_A is to automatically call the create method for Model B. Then a script takes over a generates a bunch of data for Model_B. I use after_create because this only has to happen once.
It needs done this way. If you wanna know the details feel free to ask...
So I got Model_A here. I just can't seem to get the right syntax in create_model_b. In the example I used I just get an error saying the method doesn't exist for Model_A.
class Model_A < ActiveRecord::Base
belongs_to :Model_B
after_create :create_model_b
...
def create_model_b
#so I tried a bunch of stuff here but none of it worked
#I need to create a Model_B which will contain the current Model_A id
#ex. self.model_b.create(model_a_id: self.id)
end
end
Model_B doesn't do anything special really:
class Model_B < ApplicationController
def create
#model_b = Model_B.new(model_b_params)
create_the_data
respond_to do |format|
if #model_b.save
#redirect
else
#uh oh
end
end
end
end
Thanks!
Two ways:
1.
class Model_A < ApplicationController
def create
#model_a = ModelA.new(model_a_params)
if #model_a.save
ModelB.create(model_a_id: #model_a.id, .....)
#create data for model B either here or with after_create (of model B)
redirect_to somewhere_awesome_path
else
# rescue error
render 'new'
end
end
2.
class Model_A < ActiveRecord::Base
after_create :create_model_b
...
def create_model_b
ModelB.create(model_a_id: id)
end
end
Your Model A contains half of an association: belongs_to :Model_B
Your Model B is missing its association to Model A.
Depending on the relationship you set up, you can complete the association with a has_one :Model_A, or has_many :Model_A, for example.
Here's Active Record documentation for reference.
Related
I have models with variables (many model classes : polymorphic relation), and constraints between variables (variables are not necessarily in the same model).
I try to make a query to find all constraints associated to a list of models (with all vars associated to the models in list), and I really don't know how to do it.
My models looks like this.
class Model1 < ApplicationRecord
has_many :vars, as: :model
end
class Model2 < ApplicationRecord
has_many :vars, as: :model
end
class Var < ApplicationRecord
belongs_to :model, polymorphic: true
# model_type and model_id in vars table
has_many :cns_vars
has_many :constraints, through: :cns_vars
end
class_CnsVar < ApplicationRecord
belongs_to :var
belongs_to :constraint
end
class Constraint < ApplicationRecord
has_many :cns_vars
has_many :vars, through: :cns_vars
end
To find constraints related to one model I have this query :
Constraint.includes(:vars).where(active: true, vars: {model_id: model.id, model_type: model.class.to_s})
This query give me the constraints that have at least one var associated to my model.
I need constraints with all vars associated to a list of models.
Is there a way to make the same query, but with all vars associated to the model ?
Is there a way to make the same query, but with all vars associated to a list of models ?
Constraint.includes(:vars).where(active: true, vars: {*[var.model_type, var.model_id] in my models list*})
Is there a solution to do this with one query ?
Or do I have to do it another way ?
Thanks for your help.
(ruby : 2.6.0 / rails : 5.2.3)
EDIT :
To give better explanation, look at this function that returns what I need, but this make too much queries !
def constraints_for_models_list(models)
all_vars = models.flat_map(&:vars)
all_constraints = all_vars.flat_map(&:constraints)
all_constraints.uniq!
constraints = []
all_constraints.each do |constraint|
next unless constraint.vars.included_in?(all_vars)
constraints << constraint
end
return constraints
end
Constraint.includes(:vars).where(active: true).where.not(vars: { model: nil })
of course if I correctly get the point of what you're trying.
for what you asked in comment:
Constraint.includes(:vars).where(active: true).where('vars.model_type IN
?', ['Model1',Model2'])
I kind of stuck at trying to generate statistics for my application. The relevant part of the application has the following structure:
class CarRegistration < ActiveRecord::Base
belongs_to :ride
belongs_to :car
...
end
class Car < ActiveRecord::Base
has_many :car_registration
...
end
class Ride < ActiveRecord::Base
belongs_to :passenger
belongs_to :driver
has_many :car_registration
...
end
class Driver < ActiveRecord::Base
has_many :cars
...
end
class Passenger < ActiveRecord::Base
has_many :cars
...
end
I am trying to get a list of rides, top drivers and and top passengers. I originally tried something like this:
#rides_finished = Ride.joins(:car_registration)
.select('rides.id')
.where("(car_registrations.ride_id = rides.id)
AND rides.status = 3
AND rides.driver_currency = ?
AND rides.passenger_currency = ?", currency, currency)
.distinct # against displaying one shipment multiple times
And then I tried:
#top_pasengers = #rides_finished.joins(:passenger)
.select('passengers.id, passengers.name, count(rides.passenger_id) AS count_all')
.where('rides.passenger_id IS NOT NULL')
.group('passengers.id')
.order('count_all DESC')
.limit(10)
But when I run these queries, I get
Mysql2::Error: Unknown column 'count_all' in 'order clause': ...
Any help how to get the needed numbers?
Thank you very much
Your question is a little confusing because your query uses Ride but there is no Ride in the model definitions listed. I've focussed purely on the example queries you listed.
I think it would be easier to start with a single query chain for 'top passengers':
Passenger
.select('passengers.*')
.select('count(1) as ride_count')
.joins(:rides)
.where(rides: { status: 3,
driver_currency: currency,
passenger_currency: currency })
.group('passengers.id')
.order('ride_count desc')
.limit(10)
That will get you an ActiveRecord::Relation of Passenger models that also respond to a ride_count call, e.g. you could use it like:
results.each do |p|
puts "#{p.name}: #{p.ride_count}'
end
If all that works, you should be able to adjust the query to get the top drivers.
To get the list of finished rides, I suggest a separate, simple query:
Ride.where(status: 3,
driver_currency: currency,
passenger_currency: currency)
Let me know if any of that produces an error.
I'm associating users with given firms through a join table because I need to be able to have a bunch of users with every firm and vice versa.
class User
has_many :firm_connections, dependent: :destroy
has_many :firms, through: :firm_connections
end
class FirmConnection
belongs_to :user
belongs_to :firm
end
class Firm
has_many :firm_connections
has_many :users, through: :firm_connections
end
My question is, when a user hits the index page for firms, how do I scope it to only show what those users are associated with?
class FirmPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin?
scope.all
else
scope.where #only the firms associated with that user
end
end
end
Do I need to create a scope at the firm level that accepts a #user? Or can I do this all directly inline? I could hack something together, but haven't wrapped my head around pundit yet, so any direction would be greatly appreciated!
like this:
def self.associated_with(user)
all.select { |m| m.users.include?(user) }
end
This should work for you
class Firm
def index
#firms = policy_scope(Firm)
end
end
class FirmPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin?
scope.all
else
user.firms #only the firms associated with that user
end
end
end
end
The policy doesn't always have to call it the way that you think, it just has to return something (for scopes, almost always an ActiveRecord::Relation, for regular, true or false). You could do
scope.includes(:firm_connections).where(firm_connections: { user_id: user.id })
but that's not as readable (IMO).
I have the following two Models:
class TopicContent < ActiveRecord::Base
unloadable
belongs_to :topic
end
and
class Topic < ActiveRecord::Base
unloadable
has_one :topic_content
accepts_nested_attributes_for :topic_content
end
And the following show action, which get the :id from the selected topic:
def show
#text = TopicContent.find(params[:id])
end
The problem is, that the find method always take the primary-key(id) instead of foreign-key (topic_id) from the TopicContent table.
Is there something wrong with my defined associations?
.find(primary_key) always retrieves the records from database based on primary key.
Use .find_by(conditions) instead as it finds the first record matching conditions passed to it.
For eg:
#text = TopicContent.find_by(topic_id: params[:id])
You need to find the TopicContent via the Topic.
def show
#topic = Topic.find(:topic_id)
#text = #topic.topic_content
end
This is assuming you have your routes set up as well.
I have built a user and friend relationship model but the problem is that with those associations I can friend myself. I have successfully suppressed it in my views and controller, but logically it should be suppressed in the model because I could still create the friendship from the console which I want to avoid.
User model
has_many :user_friendships
has_many :friends, through: :user_friendships,
conditions: { user_friendships: { state: 'accepted' } }
User_friendship model
belongs_to :user
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
Everything else is working perfectly like adding, blocking, deleting, requesting a friend the only problem with my model is that I can also friend myself which I want to avoid.
Add a validation to UserFriendship:
validate :cannot_friend_self
def cannot_friend_self
errors.add(:friend_id, "cannot friend self") unless user_id != friend_id
end
This issue is a little problematic because we want to remain RESTful, separate the different tasks (MVC,) and take into account of weird race conditions (Thread Safety.)
Try using validations#exclusions (http://guides.rubyonrails.org/active_record_validations_callbacks.html#exclusion)
class ApplicationController < ActionController::Base
...
before_filter do |c|
User.current_user = User.find(c.session[:user]) unless c.session[:user].nil?
end
...
end
class User < ActiveRecord::Base
...
cattr_accessor :current_user
...
end
class Friends < ActiveRecord::Base
...
validates :friend_id, :exclusion => { :in => %w(User.current_user.id),
:message => "I don't think you really want to friend yourself" }
...
end
If you want to be safe, please refer to (http://nhw.pl/wp/2011/11/30/passing-current-user-id-to-rails-models)
Disclaimer:
I wrote this possible solution without testing it (aka pulled it out of the thin air with little reference)
I have not thread with Ruby on Rails.
You probably want to throw in a validation
Such as
validate :cannot_friend_self
def cannot_friend_self
current_user.id != friend.id
end
This code may not be exactly what you want, but should point you in the right direction.
Full guide here http://guides.rubyonrails.org/active_record_validations_callbacks.html#custom-methods