I have a simple structure of "A has_many B has_many C"
If I go into Rails console and do something like A.first.Bs.first.C.create() it'll create without an issue, however, if I use the API (or even Seeds actually) and so something like POST to /api/v1/a/1/b with the below create, I will always get rejected due to "Must belong to A" - Basically meaning it's trying to save as a.id = null.
A = Campaign. B = Party for the below snippet.
def create
#campaign = Campaign.find_by_id(params[:campaign_id])
if #campaign.user_id == current_user.id
#party = Party.new(party_params)
# #party.campaign_id = params[:campaign_id]
if #party.save!
render status: 201, json: {
message: "Successfully saved the party!",
party: #party,
user: current_user
}
else
render status: 404, json: {
message: "Something went wrong: Check line 27 of Party Controller"
}
end
end
end
The line I have commented out where I manually assigned #party.campaign_id resolved the error, but I am curious why it doesn't automatically pull from the information? Do route resources not function the same way as a Campaign.first.parties.create would?
Welcome any revision to this create method; It feels bulky, and likely not secure at all presently.
(Note #campaign.user_id == current_user.id is kind of a generic catch in case someone is trying to update someone else's campaign. I will likely re-visit this logic to make it more secure.)
Rails does not find anything automatically basing on routes, you need to do it by yourself.
In this case you can either assign id basing on params (as you did in the comment) or build Party as an element of Campaign.parties association
#campaign = Campaign.find_by_id(params[:campaign_id])
#party = #campaign.parties.new(party_params)
What I need- some kind of way to grab the number entered into the form in order to check it against previous records PRIOR to updating, so that if a validation error occurs, the user can be prompted to confirm before the form is submitted. Params would work, but are only returned after the form is posted- so no help. Is there an ajax call that I can pass into a ruby variable? Or perhaps some kind of ruby code that will read the input in the text box without submitting or linking?
What I'm doing- I'm trying to set up a 'manual validation' because I don't want the validation to 'prevent' from saving. Instead, it should be more like a confirmation.
If you care for context, Here's the run-down- I have a client that pays monthly deposits. We confirm these deposits over the phone through a third party. Naturally, in order to get the most accurate data as possible, we have to account for human error and other factors. A deposit this month should never be less than a deposit last month- but deposits can be "moved" from one account to another, which would make it seem like it was less. I have a form that new data is input on, and I want it to check against previous records to see if the deposit is more or less than reported previously. If less, it should ask for confirmation- an "are you sure?" kind of thing.
The code is old & outdated, should be changed from the ground up, but would take months when I have days to do this. I'm just looking for a patch.
What I have so far- note that cur_deposit is this months and rec_deposit is last months.
<%
arr1 = []
arr2 = []
is_less = false
r = #recent_inquiries.last
r.inquiry_deposits.order(:id).each do |t|
arr1 << t.cur_deposit.to_f
arr1 << t.rec_deposit.to_f
end
#inquiry.inquiry_deposits.order(:id).each do |td|
#============THIS is the part that needs help
arr2 << params["cur_deposit_text_box"]
arr2 << params["rec_deposit_text_box"]
end
i = 0
while i < (arr1.size - 1)
comp_arr1 = []
comp_arr2 = []
comp_arr1 << arr1[i]
comp_arr1 << arr1[i + 1]
comp_arr2 << arr2[i]
comp_arr2 << arr2[i + 1]
if Inquiry.compare_deposits(comp_arr1, comp_arr2) != nil then is_less = true end
i = i + 2
end
if is_less
strConf = "A deposit from last month is greater than the same deposit this month, which should not happen. Are you sure?"
end
%>
<%= submit_tag "Save Inquiry", :onclick=>"$('#submit_form').val('Save Inquiry summary');", :class => 'tgButton3', :id => 'save_inquiry_button_bottom', :confirm => strConf %>
When I get this code working, I will stash all the functioning code into a model- I just have it in the view for testing. It is safe to assume that all the 'custom methods' this script calls to are functioning. If you need code from them, I'll happily share it.
Rails version 3.0.20
Can you use jQuery on your website? (if not it is doable in plain javascript)
$('#id-of-your-field').change(function(e){
//do here your client side logic if any needed
var yourfirstvalue = $(e.target).val();
//now take the value and send it to server (your ruby stuff)
$.ajax({
url: yourURL + "/" + yourfirstvalue,
success: function(data){
//this data can be sent as JSON in structure which suits the best to you
//so you can use it to populate your second dropdown
var values = JSON.parse(data);
//use your values
}
});
});
Google "combo box example" it might help you.
In order to close this question out, and in case anybody else is wondering, I will answer my own question. This is what I've found out.
Because of the nature of the relationship between client & server, there is really no way to get the value of the text input, store it in a ruby variable, and check it against another ruby variable. Ruby script only runs once and then is rendered, so while ajax may be able to continually run in the background and gather inputs, etc, the integration with ruby falls short when talking client-side only interaction. (Correct me if I'm wrong- after all, I posted the question to get everybody's input!)
The fix: I created a switch using hidden tags. When the form loads, the hidden tag is blank. After submitting the form, the update action checks the params of the newly entered data against the numbers from last month. If the conditions check out, it saves. If not, it re-loads the page with a message. If the message is confirmed, an ajax command changes the hidden tag to "true" which bypasses the comparison once it hits the update action again. Otherwise, the data is not saved. Problem solved!
I'm making this a community wiki answer in case anybody would like to add their two cents.
I am a Rails newbie. I want to use Koala's Graph API.
In my controller
#graph = Koala::Facebook::API.new('myFacebookAccessToken')
#hello = #graph.get_object("my.Name")
When I do this, I get something like this
{
"id"=>"123456",
"name"=>"First Middle Last",
"first_name"=>"First",
"middle_name"=>"Middle",
"last_name"=>"Last",
"link"=>"http://www.facebook.com/MyName",
"username"=>"my.name",
"birthday"=>"12/12/1212",
"hometown"=>{"id"=>"115200305133358163", "name"=>"City, State"}, "location"=>{"id"=>"1054648928202133335", "name"=>"City, State"},
"bio"=>"This is my awesome Bio.",
"quotes"=>"I am the master of my fate; I am the captain of my soul. - William Ernest Henley\r\n\r\n"Don't go around saying the world owes you a living. The world owes you nothing. It was here first.\" - Mark Twain",
"work"=>[{"employer"=>{"id"=>"100751133333", "name"=>"Company1"}, "position"=>{"id"=>"105763693332790962", "name"=>"Position1"}, "start_date"=>"2010-08", "end_date"=>"2011-07"}],
"sports"=>[{"id"=>"104019549633137", "name"=>"Sport1"}, {"id"=>"103992339636529", "name"=>"Sport2"}],
"favorite_teams"=>[{"id"=>"105467226133353743", "name"=>"Fav1"}, {"id"=>"19031343444432369133", "name"=>"Fav2"}, {"id"=>"98027790139333", "name"=>"Fav3"}, {"id"=>"104055132963393331", "name"=>"Fav4"}, {"id"=>"191744431437533310", "name"=>"Fav5"}],
"favorite_athletes"=>[{"id"=>"10836600585799922", "name"=>"Fava1"}, {"id"=>"18995689436787722", "name"=>"Fava2"}, {"id"=>"11156342219404022", "name"=>"Fava4"}, {"id"=>"11169998212279347", "name"=>"Fava5"}, {"id"=>"122326564475039", "name"=>"Fava6"}],
"inspirational_people"=>[{"id"=>"16383141733798", "name"=>"Fava7"}, {"id"=>"113529011990793335", "name"=>"fava8"}, {"id"=>"112032333138809855566", "name"=>"Fava9"}, {"id"=>"10810367588423324", "name"=>"Fava10"}],
"education"=>[{"school"=>{"id"=>"13478880321332322233663", "name"=>"School1"}, "type"=>"High School", "with"=>[{"id"=>"1401052755", "name"=>"Friend1"}]}, {"school"=>{"id"=>"11482777188037224", "name"=>"School2"}, "year"=>{"id"=>"138383069535219", "name"=>"2005"}, "type"=>"High School"}, {"school"=>{"id"=>"10604484633093514", "name"=>"School3"}, "year"=>{"id"=>"142963519060927", "name"=>"2010"}, "concentration"=>[{"id"=>"10407695629335773", "name"=>"c1"}], "type"=>"College"}, {"school"=>{"id"=>"22030497466330708", "name"=>"School4"}, "degree"=>{"id"=>"19233130157477979", "name"=>"c3"}, "year"=>{"id"=>"201638419856163", "name"=>"2011"}, "type"=>"Graduate School"}],
"gender"=>"male",
"interested_in"=>["female"],
"relationship_status"=>"Single",
"religion"=>"Religion1",
"political"=>"Political1",
"email"=>"somename#somecompany.com",
"timezone"=>-8,
"locale"=>"en_US",
"languages"=>[{"id"=>"10605952233759137", "name"=>"English"}, {"id"=>"10337617475934611", "name"=>"L2"}, {"id"=>"11296944428713061", "name"=>"L3"}],
"verified"=>true,
"updated_time"=>"2012-02-24T04:18:05+0000"
}
How do I show this entire hash in the view in a good format?
This is what I did from what ever I learnt..
In my view
<% #hello.each do |key, value| %>
<li><%=h "#{key.to_s} : #{value.to_s}" %></li>
<% end %>
This will get the entire thing converted to a list... It works awesome if its just one key.. but how to work with multiple keys and show only the information... something like
when it outputs hometown : City, State rather than something like
hometown : {"id"=>"115200305133358163", "name"=>"City, State"}
Also for education if I just say education[school][name] to display list of schools attended?
The error i get is can't convert String into Integer
I also tried to do this in my controller, but I get the same error..
#fav_teams = #hello["favorite_teams"]["name"]
Also, how can I save all these to the database.. something like just the list of all schools.. not their id no's?
Update:
The way I plan to save to my database is.. lets say for a user model, i want to save to database as :facebook_id, :facebook_name, :facebook_firstname, ...., :facebook_hometown .. here I only want to save name... when it comes to education.. I want to save.. school, concentration and type.. I have no idea on how to achieve this..
Looking forward for help! thanks!
To show the hash in a pretty-printed way, use the gem 'awesome_print'.
Add this to your Gemfile:
gem 'awesome_print'
And then run:
bundle install
And then, in your view, you can add:
<%= ap #hello %>
The question of how to store in the database requires a little more information on what you plan to do with it, but at minimum you could create a model, add a 'facebook_data' (type would be 'text') on that model, and then serialize it (add this line near the top of your model file: serialize :facebook_data). Then you could assign the hash (#hello in this case) to the model's 'facebook_data' property, and then save the model. But you won't be able to query your database for individual attributes of this facebook data very easily this way.
you can just do #hello["name"] then it will give you the value of the name
Your #hello object should be of the class Koala::Facebook::API::GraphCollection or something similar. You should be able to loop through this object, like your question demonstrates. As for what code to put inside your loop that will help you save records to the database, assuming your rails user model class name is User, try something like this:
#hello.each do |h|
u = User.where(:facebook_id => h["id"]).first_or_initialize
u.update_attributes(
:name => h["name"],
:first_name => h["first_name"],
:hometown_city => h["hometown"]["name"].split(",").first,
:hometown_state => h["hometown"]["name"].split(",").last.strip
# ETC, ETC
)
end
In the case of the hometown and education fields, you're just going to have to traverse the ruby hash the proper way. See the docs for more info.
.row
.nine.columns.centered
%ul.bucketlist
- #buckets.each_with_index do |resource, index|
%a{:href => "#{bucket_path(resource)}"}
%li.bucket
%h4= index + 1
%h5= resouce.name
%a{:href => "#{new_bucket_path}"}
%li.bucket.empty
= image_tag "add.gif"
%h5 Add Bucket
I have the above code written in 3 different views, with only minor differences between them. This doesn't seem very DRY to me, so I'm looking for some help to clean this up.
Between the views only a few things vary:
#buckets.each - The #buckets collection needs to change between #notes, #units aswell.
#{bucket_path} - I'd like to be able to pass in a variable so that bucket_path becomes resource_path.
If anyone can offer any help, it'd be much appreciated.
My experience with haml is limited, but I think you should be able to put the common code into a partial (a file named _common.html.haml, for instance), and then in the view simply do:
= render 'common', :items => #buckets, :new_item_path => new_bucket_path
Then change the partial like this:
%ul.bucketlist
- items.each_with_index do |resource, index|
%a{:href => url_for(resource)}
%li.bucket
%h4= index + 1
%h5= resouce.name
%a{:href => "#{new_item_path}"}
%li.bucket.empty
= image_tag "add.gif"
%h5 Add Item
One solution could be writing a helper function to generate the html.
People typically don't like html in helpers, but in this case it
would be a good idea. Write a function where you pass in the resource
name and it generates this code for you
Another way is to check the controller you are in and generate the required code based on that. For instance
resource = #buckets if params[controller]=='bucket'
A more condensed way to remove if statements would be something like following, but i havnt tried it out.
exec "resource = ##{params[:controller]}s"
Let me know if you need more help.
I am just wondering if it is possible to have a condition that passes information to the request body once it is complete, I doubt conditions can do it and are the right place even if they could, because it implies they are to do conditional logic, however the authorisation example also redirects so it has a blur of concerns... an example would be something like:
set(:get_model) { |body| { send_to_request_body(Model.new(body)) } }
get '/something', :get_model => request.body.data do
return "model called #{#model.name}"
end
The above is all psudocode so sorry for any syntax/spelling mistakes, but the idea is I can have a condition which fetches the model and puts it into some local variable for the body to use, or do a halt with an error or something.
I am sure filters (before/after) would be a better way to do this if it can be done, however from what I have seen I would need to set that up per route, whereas with a condition I would only need to have it as an option on the request.
An example with before would be:
before '/something' do
#model = Model.new(request.body.data)
end
get '/something' do
return "model called #{#model.name}"
end
This is great, but lets say I now had 20 routes, and 18 of them needed these models creating, I would need to basically duplicate the before filter for all 18 of them, and write the same model logic for them all, which is why I am trying to find a better way to re-use this functionality. If I could do a catch-all Before filter which was able to check to see if the given route had an option set, then that could possibly work, but not sure if you can do that.
In ASP MVC you could do this sort of thing with filters, which is what I am ideally after, some way to configure certain routes (at the route definition) to do some work before hand and pass it into the calling block.
Conditions can set instance variables and modify the params hash. For an example, see the built-in user_agent condition.
set(:get_model) { |body| condition { #model = Model.new(body) } }
get '/something', :get_model => something do
"model called #{#model.name}"
end
You should be aware that request is not available at that point, though.
Sinatra has support for before and after filters:
before do
#note = 'Hi!'
request.path_info = '/foo/bar/baz'
end
get '/foo/*' do
#note #=> 'Hi!'
params[:splat] #=> 'bar/baz'
end
after '/create/:slug' do |slug|
session[:last_slug] = slug
end