how to use different model in different controller - ruby-on-rails-3

In my Rails App, there's home_controller.rb, in which I'd like to use un-related table(User model).
When I access example.com/home/index, I'd like it to send message to 4th id person in User table.
I'm using mailboxer gem to send message.
I added these to home_controller.rb
class HomeController < ApplicationController
def index
receipt = User.find(4)
receipt.send_message(receipt, "Body2", "subject2")
end
end
in home model, it's totally empty.
It certainly sends message. But it sends to 1st id person, who is current user.
How can I fix this?

Sounds like the send_message method delivers email to the object that receives the method call, not the object in the first argument. Try calling
receipt.send_message(receipt, "Body", "subject")

Related

In a Rails ActiveRecord model, is using after_initialize callbacks a very bad idea?

Let's suppose we have this model
class Account < ActiveRecord::Base
after_initialize :set_name
def set_name
self.name = ‘My Account’
end
end
Now I want run a query that returns only some attributes of the model but not all of them, in particular is not returning the "name" attribute that it is used in after_initialize callback
Account.group(:name).select("count(*), id").first
And then this execution raises the following error because the set_name callback uses an attribute that has not been "loaded" or selected into the records returned by the query.
ActiveModel::MissingAttributeError: missing attribute: name
Fortunately for some particular cases I can execute the same sql query without using the Account model at all to get the desired result
sql = Account.group(:name).select("count(*), id").to_sql
ActiveRecord::Base.connection.execute(sql).first
=> #<Mysql2::Result:0x00000106eddbc0>
But the point is, what if I want to get Account objects instead of a Mysql2::Result one? Should the .select method return "complete" objects with all their attributes (e.g. filling the missing columns with Nil's)? Or is just a very bad idea to use after_initialize callbacks for our ActiveRecord models? Of course we can also add some code in the callback to check if the property exists or not but, in my opinion, this is unnatural or sounds weird working in an OO language.
Most uses of after_initialize can be (and SHOULD be) replaced with defaults on the corresponding database columns. If you're setting the property to a constant value, you may want to look into this as an alternative.
EDIT: if the value isn't constant, a call to has_attribute?(:name) will guard against this error - ActiveModel::MissingAttributeError occurs after deploying and then goes away after a while
No, it is not a bad idea, in fact I use it very often at work. The valid use case for this would be when you want code to run before you try and do anything with the object. Here is a breakdown of some of the filters offered.
# Before you intend to do anything with the object
after_initialize
# Before you intend to save the object
before_save
# After you've saved the object
after_save
# Before you save a new record
before_create
# After you create a new object
after_create

RAILS 3 - Transactions in controllers

I have an example Action in a Controller.
def some_action
product = Product.new
product.name = "namepro"
if product.save
client.update_attribute(:product_id,product.id)
end
end
How to add transactions for this code? I try with this example code:
def some_action
**transaction do**
product = Product.new
product.name = "namepro"
if product.save
client.update_attribute(:product_create,Time.now)
end
**end**
end
But it produces this error:
undefined method `transaction'
I read about using transactions in Controllers is a bad practice but I don't know why is the reason (http://markdaggett.com/blog/2011/12/01/transactions-in-rails/)
In the example, if product has been created and saved and the client update fail... Rails must not do nothing.
thanks.
You can use a transaction in a controller if you really want to. As you noted, it's bad practice, but if you want to do it, just call Product.transaction do instead of transaction do. transaction is a class method on ActiveRecord::Base, so you need to call it on an ActiveRecord-derived class. Any model class in your application will do (nit-picking caveat: if you are connecting to different databases for different models, that may not be true...but you're probably not doing that).
The reason this is a bad practice is that it doesn't properly separate concerns according to the MVC paradigm. Your controller shouldn't be so concerned with your data persistence implementation. A better approach would be to add a method to Product. Maybe something like this:
def save_and_update_create_time
transaction do
if save
client.update_attribute(:product_create, Time.now)
end
end
end
Then instead of calling product.save in your controller, call product.save_and_update_client_create_time. You may need to pass client to that method too; it's unclear from your code where client comes from. If it's an attribute on product, then the method above should work.
There are better, more Railsy ways to do this, too, especially if a product knows about its client without needing any controller data. Then you can just use an after_save callback, like this (add to Product class):
after_save :update_client
private
def update_client(product)
product.client.update_attribute(:product_create, Time.now)
end
Then every time a Product is saved, the field on the associated client will be updated. You'll possibly have to introduce some code to check for the existence of a client first.
The benefit to using callbacks, besides cleaner code, is that the entire callback chain runs in a single transaction along with the save; you don't need to create the transaction manually. You can read more about callbacks in the Rails documentation.

how do I separate user params vs Action Pack params?

I have a Rails application where user parameters are all provided via a RESTful API with JSON parameters. Specifically, there is no client-side HTML form from which the user posts data: it's raw JSON.
So to create a new Car entry, the user might:
POST www.mysite.com/api/car
model=Ford&year=2012
In my app, by the time I receive this, the Action Pack values are intermingled with the user values in the params[] hash, so I get:
params = {:model=>"Ford", :year=>"2012", :format=>"json", :action=>"create", :controller=>"api/cars"}
What's the best way to separate the user-generated parameters from parameters generated by Action Pack? The best I can think of is to delete the latter:
car_params = params.reject {|k,v| [:format, :action, :controller].member?(k)}
car = car.new(car_params)
but that doesn't smell right. Is there a better way? (For example, can I get Action Pack to encapsulate the user supplied params into a single hash and pass that as a single element of params[]?)
Don't know if it can help, but I'd just create a method in application_controller :
def user_params
return params.reject {|k,v| [:format, :action, :controller].member?(k)}
end
So throughout the code, you can just use user_params when you don't want ActionPack params

Parsing request.request_parameters in Rails

I'm building a web service app and I'm trying to handle nicely a 422 page sending back to the user the JSON the POSTed to better debug the error. To do this, I use request.request_parameters which get me back the JSON I sent, but it happens to be organized (for me) in a wired way and I can't really get it back only with the original data
What I send as JSON is this.
{
"name":"New set intensity",
"properties":
[
{"uri":null,"value":"on"},
{"uri":"https://type.lelylan.com/properties/intensity","value":"100.0"}
]
}
What I get from request.request_parameters is this.
{"{\"name\":\"New set intensity\",\"properties\":"=>{"{\"uri\":null,\"value\":\"on\"}, {\"uri\":\"https://type.lelylan.com/properties/intensity\",\"value\":\"100.0\"}"=>{"}"=>nil}}}
My main problem is that somehow the content becomes the key, and this recursively inside. Is there a way to get back the clean data? Thanks a lot.
UPDATE: I'm trying to better understand where and why this problem occurs.
In my controller I tried to access in the two available ways I know.
# request.body.read.inspect
"{\"name\":\"New set intensity\",\"properties\":[{\"uri\":\"not_valid\"}]}"
# request.request_parameters
{"{\"name\":\"New set intensity\",\"properties\":"=>{"{\"uri\":\"not_valid\"}"=>{"}"=>nil}}}
The request is made from Capybara
page.driver.post(#uri, #params.to_json)
The controller returns only JSON so this is the way I defined it. I din't put 'respond_to' and 'respond_with' and when I make the request it renders the json view show.rabl.json. This makes me think that it recognize the correct format.
class FunctionsController < ApplicationController
before_filter
...
def index
...
end
def show
..
end
def create
body = JSON.parse(request.body.read)
#function = Function.new(body)
if #function.save
render 'show', status: 201, location: FunctionDecorator.decorate(#function).uri
else
render_422 "notifications.resource.not_valid", #function.errors
end
end
Thanks.

finding id of nested attribute

I am very new to RoR so this may be very fundamental. My structure keeps getting a level deeper and I can't figure out how to find the id anymore.
First you have a Company which can have many Users. Users sign in and are authenticated and the current_user is saved in a cookie with the Session.
Since the User has one Company I can always find the Company.id through the current_user.
Next a Company has many Farms. In farms create I can get the company id from the user cookie and the farm id is new so that works, and in farm show Rails knows which farm it is supposed to show. So that level works.
Now I want to add that a Farm has many Blocks. I am adding Blocks through the associated Farm show page, but the Blocks_controller doesn't know what farm page it is on (as far as I can tell, if it can any info is appreciated).
Here is the FarmsController create that works:
def create
company_id = current_user.company_id
#company = Company.find(company_id)
#farm = #company.farms.build(params[:farm])
if #farm.save
flash[:success] = "farm created"
redirect_to root_path
else
render 'pages/home'
end
end
And this code just complains that it doesn't know what id I am talking about:
BlocksController
def create
#farm = Farm.find(params[:id])
#block = #farm.blocks.build(params[:block])
end
This is displaying on the associated Farm show page, so if there is a way to capture the id I would love to know what it is.
Thank you for your time.
The three easiest ways to get that id is to:
Pass in that farm_id using a hidden form field. When creating the link to your blocks/new form just pass in the farm_id ie use a path like new_blocks_path(:id => #farm.id) inside your blocks controller you will want to make sure that the farm_id is set on the Block model.
def new
#block = new Block
#block.farm_id = params[:farm_id]
end
Then if you are using form for the farm_id field (which should probably be of type hidden), it should contain the right id. Now change the first line in the "create" block method to
#farm = Farm.find(params[:block][:farm_id])
You can combine the process of adding the blocks and the farms using nested forms. Take a look at http://railscasts.com/episodes/196-nested-model-form-part-1 for how to do this.
You can use nested RESTful resources to make sure that within the blocks controller you always have access to the farm id. For more information about how to do this try take a look at http://railscasts.com/episodes/139-nested-resources