I am making an application where each user has access to multiple properties and can set assumptions for each property they have access to for modelling cashflows.
So user 1 has access to property 1 and sets assumptions that rent is 10k. user 2 has access to property 1 and sets assumptions that rent is 20k. Now if User 1 wants to calculate the NPV of rents over next 10 years then I need to use 10k and if user 2 wants NPV then need to use 20k.
I was thinking of implementing NPV of rent in Property Model, however then it will require current_user. Any other solution?
I would pass current_user to the model method, when you call it in the controller. That's a common technique.
# controller
def action
Model.calculate_npv(current_user)
end
Related
I want to implement a simple discount coupon. I have a model that valid coupons are saved (beside some other things) and a Product model that product features are stored (name, price, ...).
I have a simple form that enables the user to enter his coupon. I should check it to see if it is valid or not (I defined a scope for it). If the entered coupon is valid, I have to update both of the mentioned tables. In the first one, I have to change the coupon to "used" and in the second table, I should update the price with the new value. And I want to do these operations when the user entered a value in the form.
What is your suggestion and solution to do both of them? As these two operations are related to 2 different models and controllers, I cannot access them in one controller. What is the best way to call a method to do these operations? Could you please give me a clear explanation?
You have access to both models in either controller however to do this the "rails way" you should put this logic in your model. I would add a before_update callback in your coupon model that checks if the coupon is being changed to "used" as you mention. If so, you can then update its "price" in your product table. The key concept to takeaway from this is that you can call all Models from anywhere and they are not limited to their respective controllers only.
I have a situation where the user model is used multiple times in the same query in different places. For example: I want to iterate through all the groups the users is a member of, and get a unique list of all his/her friends that are also members of these groups.
Right now the user model gets reloaded every time, which results in:
1) Performance hit
2) Ideally I would use an instance variable to hold the unique list of friends, but I cannot do it since the user model gets reloaded.
It would make a lot of sense for the user model to be global for the duration of the request - any idea how I could achieve that?
Assuming that with "the user model" you actually means the current user instance (the User model is used to reference the model defined bu the class User) you normally use a memoization technique.
For instance, given you have a current_user method in your controller, you can do
def current_user
return #current if defined?(#current)
# In the following line load the current user. It's the first time
# this method is requested. Further calls will return the cached instance.
#current = ...
end
You can set a user like this:
def current_user
#current_user ||= User.find(1)
end
I am building an app in which the users can have different roles (like seller, buyer, agency, etc). So my plan is use polymorphic association, build a class for each of the roles, and associate each instance with one user account. Each user can only be of one of those types, and after reading on the subject I concluded that this is better than using STI, but correct me if I am wrong.
So the app will have different sign up screens for the main types of user accounts. For instance, in the Seller sign up form, what will happen is that the user will fill in the details required for his user account and the fields specific for the Seller profile.
So this form should create the user object, and then the seller object associated to the former. How do you handle this? My guess is that this form should correspond to the 'new' action of the sellers controller, and in the create action the user account should be created before finally creating the seller.
Is this correct? If so, should I call the User controller create action from the Seller controller, or call directly the User model? If it's the former please provide some example code, because I am not sure about how I should call one controller from another.
EDIT: I also considered using a multipart form, which is probably easier, but before deciding I want to check out this option.
If you're bent on doing it this way, I'd say just call the model from the create method of the Seller controller. What type of relationship do you have between the User model and the Seller model? Because you'd need to do something like this:
def create
user = User.create(params[:user])
seller = Seller.new(params[:seller])
seller.user_id = user.id
seller.save
redirect_to #wherever
end
Here I just assumed you have a belongs_to :user in the Seller model. Still I would advise you to consider a gem like cancan or something to handle roles instead of this approach.
Good luck!
You can use nested form. A user has one role. You can view this railscast: http://railscasts.com/episodes/196-nested-model-form-part-1, it explained how to use nested form. You will be calling User controller when will create User and Role.
I'd take a different approach for this question. Have one roles class. Then create methods in the user class like.
def can_assign_users?
roles.map(&:name).includes('admin')
end
You might have 50 models in a few years otherwise. Plus there a plenty of gems that work like this so you can leverage them.
In Django admin, how can I restrict a user from creating more than 'n' customers?
if customer is added to the main model as an InlineModel, then you just need to specufy max_num property (docs).
If this is a main model (not inline), the simplest is IMHO to override ModelAdmin's save method and check if adding additional customer is allowed.
I read everywhere that business logic belongs in the models and not in controller but where is the limit?
I am toying with a personnal accounting application.
Account
Entry
Operation
When creating an operation it is only valid if the corresponding entries are created and linked to accounts so that the operation is balanced for exemple buy a 6-pack :
o=Operation.new({:description=>"b33r", :user=>current_user, :date=>"2008/09/15"})
o.entries.build({:account_id=>1, :amount=>15})
o.valid? #=>false
o.entries.build({:account_id=>2, :amount=>-15})
o.valid? #=>true
Now the form shown to the user in the case of basic operations is simplified to hide away the entries details, the accounts are selected among 5 default by the kind of operation requested by the user (intialise account -> equity to accout, spend assets->expenses, earn revenues->assets, borrow liabilities->assets, pay debt assets->liabilities ...) I want the entries created from default values.
I also want to be able to create more complex operations (more than 2 entries). For this second use case I will have a different form where the additional complexity is exposed.This second use case prevents me from including a debit and credit field on the Operation and getting rid of the Entry link.
Which is the best form ? Using the above code in a SimpleOperationController as I do for the moment, or defining a new method on the Operation class so I can call Operation.new_simple_operation(params[:operation])
Isn't it breaking the separation of concerns to actually create and manipulate Entry objects from the Operation class ?
I am not looking for advice on my twisted accounting principles :)
edit -- It seems I didn't express myself too clearly.
I am not so concerned about the validation. I am more concerned about where the creation logic code should go :
assuming the operation on the controller is called spend, when using spend, the params hash would contain : amount, date, description. Debit and credit accounts would be derived from the action which is called, but then I have to create all the objects. Would it be better to have
#error and transaction handling is left out for the sake of clarity
def spend
amount=params[:operation].delete(:amount)#remove non existent Operation attribute
op=Operation.new(params[:operation])
#select accounts in some way
...
#build entries
op.entries.build(...)
op.entries.build(...)
op.save
end
or to create a method on Operation that would make the above look like
def spend
op=Operation.new_simple_operation(params)
op.save
end
this definitely give a much thinner controller and a fatter model, but then the model will create and store instances of other models which is where my problem is.
but then the model will create and store instances of other models which is where my problem is.
What is wrong with this?
If your 'business logic' states that an Operation must have a valid set of Entries, then surely there is nothing wrong for the Operation class to know about, and deal with your Entry objects.
You'll only get problems if you take this too far, and have your models manipulating things they don't need to know about, like an EntryHtmlFormBuilder or whatever :-)
Virtual Attributes (more info here and here) will help with this greatly. Passing the whole params back to the model keeps things simple in the controller. This will allow you to dynamically build your form and easily build the entries objects.
class Operation
has_many :entries
def entry_attributes=(entry_attributes)
entry_attributes.each do |entry|
entries.build(entry)
end
end
end
class OperationController < ApplicationController
def create
#operation = Operation.new(params[:opertaion])
if #operation.save
flash[:notice] = "Successfully saved operation."
redirect_to operations_path
else
render :action => 'new'
end
end
end
The save will fail if everything isn't valid. Which brings us to validation. Because each Entry stands alone and you need to check all entries at "creation" you should probably override validate in Operation:
class Operation
# methods from above
protected
def validate
total = 0
entries.each { |e| t += e.amount }
errors.add("entries", "unbalanced transfers") unless total == 0
end
end
Now you will get an error message telling the user that the amounts are off and they should fix the problem. You can get really fancy here and add a lot of value by being specific about the problem, like tell them how much they are off.
It's easier to think in terms of each entity validating itself, and entities which depend on one another delegating their state to the state of their associated entries. In your case, for instance:
class Operation < ActiveRecord::Base
has_many :entries
validates_associated :entries
end
validates_associated will check whether each associated entity is valid (in this case, all entries should if the operation is to be valid).
It is very tempting to try to validate entire hierarchies of models as a whole, but as you said, the place where that would be most easily done is the controller, which should act more as a router of requests and responses than in dealing with business logic.
The way I look at it is that the controller should reflect the end-user view and translate requests into model operations and reponses while also doing formatting. In your case there are 2 kinds of operations that represent simple operations with a default account/entry, and more complex operations that have user selected entries and accounts. The forms should reflect the user view (2 forms with different fields), and there should be 2 actions in the controller to match. The controller however should have no logic relating to how the data is manipulated, only how to receive and respond. I would have class methods on the Operation class that take in the proper data from the forms and creates one or more object as needed, or place those class methods on a support class that is not an AR model, but has business logic that crosses model boundaries. The advantage of the separate utility class is that it keeps each model focused on one purpose, the down side is that the utility classes have no defined place to live. I put them in lib/ but Rails does not specify a place for model helpers as such.
If you are concerned about embedding this logic into any particular model, why not put them into an observer class, that will keep the logic for your creation of the associated items separate from the classes being observed.