Create dependant record on Clearance user creation - ruby-on-rails

I simply want to create another record when the user signs up. I think the following are the only places where Clearance touches my app, not counting the views.
class ApplicationController < ActionController::Base
include Clearance::Controller
before_action :require_login
.
.
.
end
class User < ActiveRecord::Base
include Clearance::User
has_many :received_messages, class_name: 'Message', foreign_key: :receiver_id
has_one :privilege
end

You want after_create (or perhaps before_create, or some other hook, depending on your semantics), which is provided by Rails independent of Clearance. It lets you declare a method to run after your User record is created, and the method can create other objects that you want to exist.
class User < ActiveRecord::Base
after_create :create_other_thing
private
def create_other_thing
OtherThing.create(other_thing_attributes)
end
end
Be aware than after_create runs in the same transaction as your User creation, so if there's an exception during OtherThing.create, both it and the User will be rolled back.
Check out Active Record Callbacks for full details on how ActiveRecord lifecycle hooks work.

Related

How to generate Child objects each time a parent object is created automatically on rails 5.1

In my application i have the following models:
class Bus < ApplicationRecord
belongs_to :user
has_many :seats, dependent: :destroy
end
class Seat < ApplicationRecord
belongs_to :bus
end
Is there a way to have a specific number of "Seats" created each time a user adds a bus? I don't want users to be creating seats for the buses.
You can hook creation of child object to after_create callback
https://guides.rubyonrails.org/active_record_callbacks.html
class Parent < ApplicationRecord
# register callback
after_create :createChilds
private
def createChilds
# create required amount of childs
end
end
You can use callbacks for this purpose, specifically after_create one.
class Bus
DEFAULT_SEATS_COUNT = 50.freeze
after_create :add_seats
private
def add_seats
DEFAULT_SEATS_COUNT.times do
# This logic can be more complicated if you need different attribute values for different seats.
self.seats.create!
end
end
end

ensure association is created or saved after primary model has been saved and created Rails 4

I have these 2 models as follow
class Application < ActiveRecord::Base
has_many :commitments, class_name: "Commitment", \
:source => :application, dependent: :destroy
accepts_nested_attributes_for :commitments
after_create: update_case_code
end
class Commitment < ActiveRecord::Base
belongs_to :application
after_create: send_notification
def send_notification
ap self.application.case_code
end
end
class ApplicationsController < ApplicationController
def create
#application = Application.new(params)
#application.save
end
end
In my application_controller whenever i create a new Application record,a new record is also created in the Commitment and it tries to get the case_code from the application record but the after_create method of the application model hasnt been executed yet.
Is there any way to optimize this code so that it works properly?
Probably there is. Probably you can also use another callback on the application model which happens before, there are plenty of them. See Active Record Callbacks
However this is exactly the case, which other people call rails callback hell
The best practice here would be just creating a form object, which creates the data in the order you need and remove the callbacks
class ApplicationCommitmentForm
include ActiveModel::Model
attr_accessor ...
def submit
a = Application.create ..
a.update_case_code
a.commitments.create ...
end
end
See ActiveModel Form Objects
Btw you could also wrap the submit code into a transactions ensuring that either all records are created or in case of any errors nothing at all.

Rails 4.1 nested model form fields

Booking -< Orders -< Transactions
class Booking < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :booking
has_many :transactions
end
class Transaction < ActiveRecord::Base
belongs_to :order
end
I need to be able to create a Transaction without an Order or Booking existing.
I'm trying to achieve the following:
When a Transaction is created an Order and a Booking is automatically created. The transaction form can take a Booking.booking_number which will be saved to the above automatically created Booking.
I'm very new to rails and have tried a combination of accepts_nested_attributes_for, Ryan Bates' nested model form part1 screencast and form_fields_for without success.
Some guidance, not necessarily code, would be much appreciated.
My routes look like:
I need to be able to create a Transaction without an Order or Booking
existing.
Bad system design - surely a transaction would follow an order or booking?
From your question, I'd highly recommend creating a booking or order first. This will allow you to create a transaction as a bolt-on to the order or booking:
#app/controllers/bookings_controller.rb
Class BookingsController < ApplicationController
def create
booking = Booking.new(booking_params)
booking.save
end
end
#app/models/booking.rb
Class Booking < ActiveRecord::Base
before_create :build_transaction #-> creates a blank transaction which can be populated later
end
Nonetheless, there's nothing stopping you creating a transaction & assigning an order later
You can do this:
#app/controllers/transactions_controller.rb
def create
Transaction.new(transaction_params)
end
#app/models/transaction.rb
Class Transaction < ActiveRecord::Base
after_create :order
def order
self.order.create!([order_details?])
end
end
If you tell me some more about what you're building, I'll be able to create a more refined response!
Try this it may be work.
In your model
accepts_nested_attributes_for :order, :allow_destroy => true
change whether true/false depending on your form

Design considerations for creating associated records on Devise User object on registration

I'm using Devise, and for each User account created I want to generate a relationship where:
class User < ActiveRecord::Base
belongs_to :business
end
class Business < ActiveRecord::Base
has_many :users
has_one :apt_setting
has_many :hours, :as => :hourable
end
class ApptSetting < ActiveRecord::Base
belongs_to :business
end
So upon registration an associated Business object is created, and with each Business object an associated ApptSettings and BusinessHour object is created.
I currently have this implemented like this:
class Admin
before_create :create_associated_records
def create_associated_records
# create the associated business object
business = Business.create(:business_name => business_name, :subdomain => subdomain, :initial_plan => initial_plan)
# retrieve the id of the new business object
self.business_id = business.id
# create the associated records
BusinessHour.default_values(business_id)
ApptSetting.default_values(business_id)
end
end
class ApptSetting < ActiveRecord::Base
belongs_to :business
def self.default_values(business_id)
# ... create record with default values
end
end
class BusinessHour < Hour
belongs_to :hourable, :polymorphic => true
def self.default_values(business_id)
# ... create record with default values
end
end
This does work, but does it seem like the best design?
One alternative I'm considering is handling removing Admin -> create_associated_records, and instead do that work in Users::Accounts::RegistrationsController where I override the 'create' method. There I could build all the associated records, set :accepts_nested_attributes where appropriate, then call 'save' on the Business object, which should then cause all the associated records to be generated.
Thoughts on the best design, or any other ideas?
you don't need the default_values methods. In your create_associated_records you can change those calls to:
ApptSetting.create(:business_id => business_id)
Don't override the create method. before_create callbacks are a better way to go. In either case, If a business has many users, do you really want to create a new business every time a new user is created? How does a second user ever get added to a business? add something like,
def create_associated_records
return unless self.business_id.nil?
....
Also where are the business_name, subdomain, and initial_plan variables coming from in your method? Do you have them as attributes of the admin user? Seems like they should be only values of the business.
I think the biggest question here is, does a user really need a business in order to exist? Why can't the user just create their Business after they create their account?
** Edit: Being more clear / cleaner version using rails association methods:
class Admin
before_create :create_associated_records
private
def create_associated_records
return unless self.business_id.nil?
self.create_business
self.business.create_appt_setting
self.business.hours.create
end
end

Creating associations by using checkboxes

A User can only have two types of Subscriptions: DailySubscription and WeeklySubscription. When the user is at the new and edit action, I'd like them to check off either of the subscriptions they would like to get.
I'm comfortable using nested fields (as per Ryan Bates' screencast here) but I think when I add inheritance, it really complicating matters. Is there a better way?
class User < ActiveRecord::Base
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :user
# type field is defined in the migration for Single Table Inheritance
end
class DailySubscription < Subscription
# Business logic here
end
class WeeklySubscription < Subscription
# Different business logic here
end
My initial efforts with the controller are wacky:
class UsersController < ApplicationController
def new
#user = User.new
# I can't use #user. subscriptions.build as Rails doesn't
# know what type of model to add!
#user.subscriptions = [DailySubscription.new, WeeklySubscription.new]
end
...
end
I think I am conceptually really missing something here but I can't figure it out. Help!
Judging from your description, your user has only two possible subscription choices: daily and/or weekly. Therefore you dont need to have a has_many association because two has_ones would suffice(note polymorphic subscribeable below:
class User < ActiveRecord::Base
has_one :daily_subscription, :as => :subscribeable
has_one :weekly_subscription, :as => :subscribeable
end
class Subscription < ActiveRecord::Base
belongs_to :subscribeable, :polymorphic => true
# type field is defined in the migration for Single Table Inheritance
end
class DailySubscription < Subscription
# Business logic here
end
class WeeklySubscription < Subscription
# Different business logic here
end
furthermore for the controller you just need to initialize User. Upon initialization, #user.daily_subscription and weekly_subscription will be null as determined by .blank? method. When you go ahead and create the user in the create method, you will need to populate these fields with instances of corresponding subscriptions.
class UsersController < ApplicationController
def new
#user = User.new
# bam -- youre done.
end
...
end

Resources