what is complex in this method - ruby-on-rails

I have this action in my rails controler,
def step_submit
validate_user()
#owning = #user.create_user_car_transaction(Variant.find(params[:variant]), params[:details], params[:address], params[:somethin1])
Contact.user_contact(current_user, params[:contact]) if #user.contact.nil?
redirect_to "/next_step"
end
I use codeClimate to check the quality of the code..
it shows this action's complexity ~ 30 ..
I actually broke a really huge method into this.. how can i still reduce this complexity?
these are the different methods the action calls
def self.user_contact(user, contact_hash = nil)
contact = user.contact || user.create_contact()
contact.update_attributes(contact_hash) if contact_hash.present?
contact
end
def validate_user
if params[:user] && current_user.nil?
user = User.create(params[:user])
sign_in user
end
end
def create_user_car_transaction(car, details_hash, address_hash, coupon_hash = nil)
transaction = self.transactions.create()
car.transaction_item = transaction.transaction_items.create()
car.save
payment_hash = details_hash
payment_hash.merge!(address_hash)
payment = transaction.create_payment(payment_hash)
transaction.update_attributes(:status=>"1") if transaction.status.nil?
transaction
end

Related

Coupon System Order price update

Hi I'm coding coupon system rails 5.2.3 .
But I have a problem. If coupon code is entered before payment, discount is applied. But I can't update the total price if the product is deleted from the cart.
Order Model: Every update calculating price
def subtotal
price = order_items.includes(:product).collect { |oi| oi.valid? ? (oi.quantity * oi.unit_price) : 0 }.sum
end
Coupon Controller
def check_coupon_code
if #coupon = Coupon.find_by(code: params[:code])
coupın = Coupon.find_by(code: params[:code])
#order = current_order
if #coupon[:redemption_limit] > 0 and #coupon[:active] === true
#order.total_amount = current_order.subtotal - coupın.amount
#order.update(order_param)
Coupon.transaction do
Coupon.where(code: params[:code]).each do |coupon|
coupon.redemption_limit = coupon.redemption_limit - 1
coupon.save
end
end
#order.update(code_apply)
redirect_to "/cart"
flash[:notice] = 'Coupon Code Applied!'
else
redirect_to "/cart"
flash[:danger] = 'Coupon Code Invalid!'
end
else
redirect_to "/cart"
flash[:danger] = 'Coupon Code Invalid!'
end
end
Order Item Controller
def update
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.update_attributes(order_item_params)
#order_items = #order.order_items
end
def destroy
#order = current_order
#order_item = #order.order_items.find(params[:id])
#order_item.destroy
#order_items = #order.order_items
end
Based on our discussion in the comments, I'm assuming order_items have coupon_id as a field which is either empty(if no coupon code is applied), or contains the id of the code applied to order_items.
Now, updating the price of the order as per deletion could be done using a before_destroy callback in order_item model. You could do something as follows:
# order_item.rb
before_destroy :update_order_price
private
def update_order_price
# Your logic to recalculate the order price
end
NOTE: Calling another model's methods from a callback on one model can be a bit difficult to maintain in the long term. In that case, you could use an event driven mechanism in case this app becomes really large

How do I perform an ActiveRecord query after form submission?

Would this work? I want to do something like coins transfer
#logs = Logs.new(log_params)
#logs.save
#tt = Users.where(email: params[:email]).update(money: Users.find(current_user.id)['money'] - params[:money])
#tt.save
#wr = Users.find(current_user.id).update(money: Users.where(email: params[:email])['money'] + params[:money])
#wr.save
I don't know if you are planning to display those values in your views, but you could do something like this:
sender = Users.where(email: params[:email]).first
# This returns the user
recipient = Users.find(current_user.id)
# or just current_user if it inherit from the User class
money_to_substract = recipient.money - params[:money]
money_to_sum = recipient.money + params[:money]
Then your transsaction would be a bit dryier
User.transaction do
#logs = Logs.new(log_params)
#tt = sender.update(money: money_to_substract)
# update saves to the database so no need to call save
# #tt.save
#wr = recipient.update(money: money_to_sum)
# update saves to the database so no need to call save
# #wr.save
end
But IMHO, I would do something like this:
models/User.rb
class User < ActiveRecord::Base
...
def sends_money(amount)
money_to_substract = self.money - amount
update(money: money_to_substract)
end
def receives_money(amount)
money_to_sum = self.money + amount
update(money: money_to_sum)
end
...
end
In your controller
amount = params[:money].to_i
User.transaction do
#logs = Logs.new(log_params)
#tt = sender.sends_money(amount)
#wr = recipient.receives_money(amount)
end
Which makes things easier to read and follow through your code.
Hope this helps!

Why is my service not changing my instance variable?

My service is supposed to match the current user with an opponent. I have a method in my service that is supposed to find this opponent but it's not saving it in my controller. I realize this is a very basic question but I'm very new to rails, thank you!
Here is my service:
class MatchUser
attr_accessor :user_params
def initialize(user_params)
#user_params = user_params
end
def match(opponent)
return false if user_params[:matched] == true
#unmatched_users = User.where(matched: false)
#unique_unmatched_users = #unmatched_users.where.not(id: user_params[:id])
#same_league_unmatched_users = #unique_unmatched_users.where(league_id:
user_params[:league_id])
return false if #same_league_unmatched_users.empty?
opponent = #same_league_unmatched_users.sample
opponent.faceoff_date = Time.now
user_params[:faceoff_date] = Time.now
opponent.save!
end
end
Here is the part in my controller where I'm getting an error when I try to assign #matched_user_team because #matched_user is nil
#user = current_user
#matching = MatchUser.new(#user)
if #matching.match(#matched_user)
#matched_user_team = #matched_user.teams.last.chars
end

One method for two models. How to pass name of model as variable to controller?

I have two methods in two different controllers (Posts & Boards). They are almost same. The difference is only model-instance-association name. To DRY this I think to write the method in module, but how to share it between Post and Board?
def init_post_comments
#user = current_user
a = #user.posts.pluck(:id) # not very nice...
b=params[:post_ids] ||= []
b = b.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # checkbox just checked
#post = Post.find_by_id(id)
if #post.users.empty?
#post.update_attribute(:new_follow, true)
end
#user.posts << #post
end
unfollow.each do |id| # if checkbox was unchecked
#post = Post.find_by_id(id)
remove_post_from_user(#post)# here we destroy association
end
if follow.size > 0
get_post_comments_data
end
redirect_to :back
end
UPDATE Ok, if I'll move the methods to model's concern how I should work with associations here? Here #user.posts.pluck(:id) and here #user.boards.pluck(:id) with what I can replace posts and boards so it can work with both of them?
So, I did it! I don't know if it's right way, but I DRY this code.
Two controllers:
posts_controller.rb
def init_comments
if Post.comments_manipulator(current_user, params[:post_ids] ||= []) > 0
#posts = Post.new_post_to_follow
code = []
#posts.each do |post|
group = post.group
code = code_constructor('API.call')
end
Post.comments_init(get_request(code), #posts)
end
redirect_to :back
end
boards_controller.rb
def init_comments
if Board.comments_manipulator(current_user, params[:board_ids] ||= []) > 0
#boards = Board.new_board_to_follow
code = []
#boards.each do |board|# подготовка запроса
group = board.group
code = code_constructor('API.call')
end
Board.comments_init(get_request(code), #boards)
end
redirect_to :back
end
As you can see they are absolutely same.
In models board.rb and post.rb - include CommentsInitializer
And in models\concerns
module CommentsInitializer
extend ActiveSupport::Concern
module ClassMethods
def comments_manipulator(user, ids)
relationship = self.name.downcase + 's'
a = user.send(relationship).pluck(:id)
b = ids.map(&:to_i)
follow = b - a
unfollow = a - b
follow.each do |id| # start to follow newly checked obj
#obj = self.find_by_id(id)
if #obj.users.empty?
#obj.update_attribute(:new_follow, true)
end
user.send(relationship) << #obj
end
unfollow.each do |id| # remove from following
#obj = self.find_by_id(id)
remove_assoc_from_user(#obj, user)#destroy relation with current user
end
follow.size
end
def comments_init(comments, objs)
i = 0
objs.each do |obj| # updating comments data
if comments[i]['count'] == 0
obj.update(new_follow: false)
else
obj.update(new_follow: false, last_comment_id: comments[i]['items'][0]['id'])
end
i += 1
end
end
def remove_assoc_from_user(obj, user)
user = user.id
if user
obj.users.delete(user)
end
end
end
My code works. If you know how to make it better please answer!

rails redirect after create problem

Could anyone help with this problem:
Upon "create", the user is redirected to the url: model/model_id (eg post/1), instead I am redirected to models/url_encoding_object (eg posts/.%23) and there is an "406 Not Acceptable" message in the console.
Typically, upon create, the console's message is "Processing PostsController#create (for 000.0.0.0 at 2009-11-23 12:32:52) [POST]", but with this error, the message is "Processing PostsController#create to # (for 000.0.0.0 at 2009-11-23 12:32:52) [POST]"
I've seen austinfromboston's response and tried his "old fashioned but effective" solution to that similar problem, but it doesn't work for me.
Any help would be greatly appreciated
Controller Code:
# POST /groups
# POST /groups.xml
def create
#group = Group.new(params[:group])
#group.category = params[:category]
#group.user = current_user
#here we add the current user to the membership collection of the group
#membership = #group.memberships.build(params[:membership])
#membership.group = #group
#membership.user = current_user
#membership.initiator = false
#membership.membership_status_id = 2
#and here we set the current_user as the owner of the group
#group_permission = #group.group_permissions.build(params[:group_permission])
#group_permission.membership = #membership
#group_permission.group_role = GroupRole.find_by_name('Owner')
unless params[:metro_area_id].blank?
#group.metro_area = MetroArea.find(params[:metro_area_id])
#group.state = (#group.metro_area && #group.metro_area.state) ?
#group.metro_area.state : nil
#group.country = #group.metro_area.country if (#group.metro_area &&
#group.metro_area.country)
else
#group.metro_area = #group.state = #group.country = nil
end
#group.tag_list = params[:tag_list] || ''
# unless #user.is_in_group?(#group)
# #user.memberships << #group
# end
respond_to do |format|
if #group.save
flash[:notice] = :group_was_successfully_created.l
format.html { redirect_to(group_path(#group.id)) }
else
format.html {
#metro_areas, #states = setup_metro_area_choices_for(#group)
if params[:metro_area_id]
#metro_area_id = params[:metro_area_id].to_i
#state_id = params[:state_id].to_i
#country_id = params[:country_id].to_i
end
render :action => "new"
}
end
end
end
Looks like either your routes are off somewhere or your model_id parameter is not what you are expecting. Might want to check to see what that parameter is being set to.
It's also really hard to give any suggestions without seeing controller code. Can you post the method making this call?
There's a lot of superfluous code, in your controller. It still works, but you're doing a lot of things the hard way.
Your problem is this line:
format.html { redirect_to(groups_path(#group.id)) }
Which redirects to the collective groups url adding the parameter #group.id.
What it should be is
format.html { redirect_to(group_path(#group.id)) }
# POST /groups
# POST /groups.xml
def create
#group = Group.new(params[:group])
#group.category = params[:category]
#group.user = current_user
#here we add the current user to the membership collection of the group
#membership = #group.memberships.build(params[:membership])
#membership.group = #group
#membership.user = current_user
#membership.initiator = false
#membership.membership_status_id = 2
#and here we set the current_user as the owner of the group
#group_permission = #group.group_permissions.build(params[:group_permission])
#group_permission.membership = #membership
#group_permission.group_role = GroupRole.find_by_name('Owner')
unless params[:metro_area_id].blank?
#group.metro_area = MetroArea.find(params[:metro_area_id])
#group.state = (#group.metro_area && #group.metro_area.state) ? #group.metro_area.state : nil
#group.country = #group.metro_area.country if (#group.metro_area && #group.metro_area.country)
else
#group.metro_area = #group.state = #group.country = nil
end
#group.tag_list = params[:tag_list] || ''
unless #user.is_in_group?(#group)
#user.memberships << #group
end
respond_to do |format|
if #group.save
flash[:notice] = :group_was_successfully_created.l
format.html { redirect_to(groups_path(#group.id)) }
else
format.html {
#metro_areas, #states = setup_metro_area_choices_for(#group)
if params[:metro_area_id]
#metro_area_id = params[:metro_area_id].to_i
#state_id = params[:state_id].to_i
#country_id = params[:country_id].to_i
end
render :action => "new"
}
end
end
end
What is this .1 doing at the end of the line??
flash[:notice] = :group_was_successfully_created.l
I tried to run similar code in my environment and it choked on that.
It should also reference:
group_path(id)
not
groups_path(id)

Resources