How to set a default value based on the current_user? - ruby

I would like to set a default value based on the User creating it and I wonder how to do that:
class Item < ActiveRecord::Base
belongs_to :invoice
after_initialize :default_values
...
private
def default_values
self.tax_rate = current_user.tax_rate || 0
end
end
The problem is that I can't use the current_user inside the model.
This is what I've got in my controller:
def create
#invoice = Invoice.new(params[:invoice])
3.times { #invoice.items.build }
...
end
Can anybody help?

You can pass attributes to the build method, so you can remove the after_initialize ed edit the controller:
def create
#invoice = Invoice.new(params[:invoice])
3.times { #invoice.items.build( :tax_rate => current_user.tax_rate }
...
end

Related

Ruby on Rails - before_action with condition only when one attribute has been changed

In my application I've Post model with attributes title & price etc.
I have 2 before_actions that I want to run only when title has changed & other one only when price has changed.
class Post < ActiveRecord::Base
before_update :do_something_with_title
before_update :do_something_with_price
def do_something_with_title
// my code for title here
end
def do_something_with_price?
// my code for price here
end
I know I can use changed? and give before_action a if: condition, but this will apply when any attribute in post has changed and not only when title & price has changed.
Any help is appreciated!
You can use title_changed? or price_changed?
class Post < ActiveRecord::Base
before_update :do_something_with_title, if: :title_changed?
before_update :do_something_with_price, if: :price_changed?
end
You can either use
class Post < ActiveRecord::Base
before_update :do_something_with_title, if: :title_changed?
before_update :do_something_with_price, if: :price_changed?
...
end
or
class Post < ActiveRecord::Base
before_update { |post| post.do_something_with_title if post.title_changed? }
before_update { |post| post.do_something_with_price if post.price_changed? }
...
end

Filter list of users based upon one of their parameter values in rails?

I am using the following gem: https://github.com/apneadiving/Google-Maps-for-Rails
I am trying to create #users inside my controller to only display users with the parameter "status" equal to "active"
def index
#users = User.all
#hash = Gmaps4rails.build_markers(#users) do |user, marker|
marker.lat user.latitude
marker.lng user.longitude
marker.title user.title
user_link = view_context.link_to user.title, user_path(user)
marker.infowindow "<h4><u>#{user_link}</u></h4><i>#{user.address}</i>"
end
end
In views/users/index.html.erb, I have a js function.
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw #hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
and in index.json.jbuilder I have:
json.array!(#users) do |user|
json.extract! user, :id, :latitude, :longitude, :address, :status, :title
json.url user_url(user, format: :json)
end
I have tried a few matching functions in my controller, but I am unsure of where to put the IF logic, ie. is it best suited to be in the index.json.jbuilder, the index.hmtl.erb or the controller?
Probably best in the Model.
class User < ActiveRecord::Base
def self.active
where(status: true)
end
end
Then in your controller
#users = User.active

How to access ActiveModel attributes from a method call on the class?

I need to reference user#role to define an association in a module. I've tried with a block as shown below, but that doesn't work. How does Rails implement behavior like this?
class User < ActiveRecord::Base
include Profile
has_profile { |user| { class_name: "#{user.role}::Profile" }}
end
module Profile
extend ActiveSupport::Concern
module ClassMethods
def has_profile(&block)
role = ### How to access #role ? ###
class_eval do
has_one :profile, class_name: "#{role}::Profile"
end
...
You might need to do something like this. I didn't tested and I'm just supposing you can do this kind of stuff
class User < ActiveRecord::Base
include Profile
has_profile { |user| user.role }
end
module Profile
extend ActiveSupport::Concern
included do
after_initialize :_init_profile
end
def _init_profile
role = #_role_block.call(self)
# Here we do class eval on singleton so we dont change base class
# I'm not sure if this works as it is but should be close enought
class << self; self; end.class_eval do
has_one :profile, class_name: "#{role}::Profile"
end
end
module ClassMethods
def has_profile(&block)
#_role_block = block
...
This works:
module Models
module Profile
extend ActiveSupport::Concern
included do
after_initialize :_init_profile
end
module ClassMethods
def has_profile(&block)
#profile_association_block = block
end
end
def _init_profile
block = self.class.instance_variable_get :#profile_association_block
self.class.has_one :profile, block.call(self)
end

ActiveModel::MassAssignmentSecurity::Error in ApiUsersController#create

I am not able to create new api_user. Everytime I try to create it I get
Can't mass-assign protected attributes: utf8, authenticity_token, api_user, commit, action, controller
here's my model api_user.rb
class ApiUser < ActiveRecord::Base
attr_accessible :api_key, :count, :email, :name, :organization
end
controller api_users_controller.rb
class ApiUsersController < ApplicationController
#skip_before_filter :verify_authenticity_token
def new
#api_user = ApiUser.new
end
def create
#api_user=ApiUser.create(params)
render :text=>"#{#api_user.id}"
end
def destroy
#api_user=ApiUser.find(params[:id])
#api_user.destroy
render :text=>"Deleted successfully"
end
end
I am using Ruby 1.9.2 and Rails 3.2.3
In order to create the ApiUser, you should use only the correct params:
#api_user=ApiUser.create(params[:api_user])
not all the paramshash

Override a Mongoid model's setters and getters

Is there a way to override a setter or getter for a model in Mongoid? Something like:
class Project
include Mongoid::Document
field :name, :type => String
field :num_users, type: Integer, default: 0
key :name
has_and_belongs_to_many :users, class_name: "User", inverse_of: :projects
# This will not work
def name=(projectname)
#name = projectname.capitalize
end
end
where the name method can be overwritten without using virtual fields?
better use
def name=(projectname)
super(projectname.capitalize)
end
the method
self[:name] = projectname.capitalize
can be dangerous, cause overloading with it can cause endless recursion
def name=(projectname)
self[:name] = projectname.capitalize
end
I had a similar issue with needing to override the "user" setter for a belongs_to :user relationship. I came up with this solution for not only this case but for wrapping any method already defined within the same class.
class Class
def wrap_method(name, &block)
existing = self.instance_method(name)
define_method name do |*args|
instance_exec(*args, existing ? existing.bind(self) : nil, &block)
end
end
This allows you to do the following in your model class:
wrap_method :user= do |value, wrapped|
wrapped.call(value)
#additional logic here
end

Resources