Update not working with id attribute Rails 4 - ruby-on-rails

I've got below URL with get attributes sending request to the controller:
http://localhost:3000/videos/new/save_video?video_id=16&status=200&id=PhTHHldZJJQ
Constoller:
def save_video
#video = Video.find(params[:video_id])
if params[:status].to_i == 200
#video.update(:yt_youtube_id => params[:id].to_s, :is_complete => true)
Video.delete_incomplete_videos
else
Video.delete_video(#video)
end
redirect_to videos_path, :notice => "video successfully uploaded"
end
However I'm getting this error somehow:
ActiveRecord::RecordNotFound at /videos/new/save_video
Couldn't find Video with id=PhTHHldZJJQ
Is there a reason why it's not finding from :video_id?
I cannot figure this out...

ActiveRecord ids are integers. You've passed in a string to find which won't convert to an integer, so it will always fail.

It seems that it is trying to search the video using :id and not :video_id. It is possibly another gem (like CanCan), which might be trying to load the video before the action starts, in a filter. Or it might be something else in the controller, can you post the full code of the controller?
If you just want this to work, use :id as the variable to send the video id, instead of :video_id.

Related

Referencing Table Entries in Rails

I'm working on a project in rails where I have a database of products, and I'm looking to use forms to manipulate them.
However, I'm having a great deal of difficulty figuring out how to do this.
I tried to use the standard:
<%= form_for(#product) %>
...
<% end %>
to send an entry to my product controller, but that returns a nil/empty field error.
My method to remove products from inventory is below. I strongly suspect this to be highly incorrect, but I have yet to figure out how to get far enough to even receive an error with that:
def ship
#products.where(#products.code = params[:code]).quantity -= 1
end
If there is any way that anybody could guide me in the right direction, I would be highly grateful. I've been trying to figure this out for a while now.
Try like this, let me know what else do you need.
def ship
#product = Product.find_by(code: params[:code]) # or you can use :code => params[:code], but not an equal sign
#product.quantity -= 1
if #product.save
respond_to do |format|
format.html {}
format.json {}
end
end
end
where returns an array or objects.
You after negating the quantity you should save it or update product on the go
You should respond back or else you'll get template missing error, OR you can redirect to some page

"Redo" suddenly failing.

Awhile ago, I implemented an "undo" and "redo" button like in this railscasts on the paper_trail gem. Everything worked great until today when the "redo" stopped working. I haven't been able to figure out why.
Here is the relevant controller action:
def revert
#version = PaperTrail::Version.find(params[:id])
if #version.reify
#version.reify.save!(:validate => false)
view_context.reify_associations(#version)
else
#version.item.destroy
end
link_name = params[:redo] == "true" ? "undo" : "redo"
link = view_context.link_to(link_name, revert_version_path(#version.next, :redo => !params[:redo]), :method => :post)
if #version.event == "create"
flash[:success] = "Undid #{#version.event}. #{link}"
redirect_to :controller => session[:controller], action: :index
else
flash[:success] = "Undid #{#version.event}. #{link}"
redirect_to :back
end
end
It fails on the line: link = view_context.link_to(link_name, revert_version_path(#version.next, :redo => !params[:redo]), :method => :post)
With an error: ActionController:UrlGenerationError ... No route matches {:action=>"revert", :controller=>"versions", :format=>nil, :id=>nil, :redo=>false} missing required keys: [:id].
So, obviously, I followed the error to see why the :id wasn't being passed in, but it is.
In the parameters:
{"_method"=>"post",
"authenticity_token"=>"6/B1YDXqZ62+DqMMdcYTfCTIJGaVvc1RjKmxWW2GkeQ=",
"redo"=>"true",
"id"=>"29"}
The id is clearly defined and the first line of this controller finds the corresponding version in the table based on that id.
I cannot figure out what is wrong here so any help would be greatly appreciated.
For anyone finding this later on, the issue I was having was the first statement of my conditional (#version.reify) never returned nil. This is because I had overwritten the object attribute to add additional information to create events. To solve the problem, I simply changed the conditional to check the type of event, i.e.
if #version.event == "create"
...
end
PaperTrail's reify method looks at the object attribute of #version and recreates the object from the serialization. It returns nil whenever the object field is nil, otherwise it will return the object it unserialized.

How do you call a model's show url from a Rail create controller?

I'm having trouble calling a model's show path from within a create controller.
I'm using the Koala gem in a Rails 3.2 app. I'm trying to publish to Facebook's open graph automatically when a User creates a particular record type.
I have a page set up with all the required FB meta tags.
I can run the Koala methods from the console and everything works fine.
But if I try to run this from the controller I get an error.
My controller looks like this:
def create
#fb_model = current_user.fb_models.build(params[:fb_model])
if #fb_model.save
Koala::Facebook::API.new(app_token).put_connections( current_user.fb_uid, "namespace:action", :object => fb_model_url(#fb_model) )
respond_to do |format|
format.html { redirect_to(#fb_model, :notice => 'Successfully created.') }
format.xml { render :xml => #fb_model, :status => :created, :location => #fb_model }
end
else
respond_to do |format|
format.html { render :action => "new" }
format.xml { render :xml => #fb_model.errors, :status => :unprocessable_entity }
end
end
end
When I create a record, my logs show:
Koala::Facebook::APIError (HTTP 500: Response body: {"error":{"type":"Exception","message":"Could not retrieve data from URL."}}):
If I edit the controller to use a static url for testing, everything works fine.
...
if #fb_model.save
Koala::Facebook::API.new(app_token).put_connections( current_user.fb_uid, "namespace:action", :object => "http://myapp.com/fb_model/2" )
...
Why can't I pass the record's url to FB from within the create controller using fb_model_url(#fb_model)?
I eventually got to the bottom of this. It's actually a really frustrating issue, as there is no indication that this is the problem in any logs or elsewhere.
The problem was that I was deploying/ testing on Heroku, and only had 1 web dyno running. My app was unable to handle both the Facebook request and the post/ get simultaneously, causing the error.
This has been addressed in another question Facebook Open Graph from Rails Heroku. It's really not what I was expecting, and I didn't come across this question in any of my earlier searching. Hopefully this can help someone else.
I solved the issue by switching from thin to unicorn.
build is finalised when the parent model is saved, and you dont seem to be operating on a parent.
I think you actually want this:
#fb_model = current_user.fb_models.new(params[:fb_model])
Also you seem to be calling #fb_model.save twice which is wrong.
Thanks for posting your findings - I've been dealing with this issue for the past couple of days and wouldnt have figured that. So when you simply increased your dyno load, you no longer had this error? I was on the verge of just using the Javascript SDK even though my 'put_connections' callbacks work in the heroku console.

Repopulating page with previous values in rails

I have a validation that needs to be done in controller. If it fails I need to go back to the view action back again with all values populated as it is on the page.
Is there a simple way to do that (using incoming params map).
This is the basic way all Rails controllers and scaffolds work. Perhaps you should try generating scaffolds?
def create
#banner_ad = BannerAd.new(params[:banner_ad])
if #banner_ad.save
flash[:notice] = 'BannerAd was successfully created.'
redirect_to :action => "show", :id => #banner_ad
else
render :action => "new"
end
end
end
I populate a #banner_ad here, attempt to save it, if it fails, I return to the form and the #banner_ad object is available to me. I then need to have a form that uses the Rails form helpers to populate the values from the object.
Depends on the flow of your app, really.
If the validation fails, you could pull the data out fo the database ...
if invalid?
#model = model.find(:id
end
Otherwise you might need to store the original values in hidden fields in the view and use those.

Rails Rendering Action in Different Controller

So I have a controller called Music with one action which is index. On the music/index.html page I list out a bunch of Songs (via a Song model) and at the bottom I have a for to create a new Song.
Song has validations which I have tested and work just fine. When the new Song saves in controller Songs action create I redirect_to => 'music_index_path' so the person can see the new song in the list. However when the Song does not save (does not pass validations) then I cannot use redirect_to since the form error_messages do not carry over. I need to use render but cannot say render :controller => 'music', :action => 'index.
My goal is to be able to show the error messages for the Song form ON the music/index.html page.
How should I go about this. I am open to other ideas (like changing up controllers) as well.
Thanks!
It sounds to me like Music should be a part of Song, or the other way around. You can always use routes to disguise it as one or the other to the user.
song/index sounds to me like it should display all songs, which is all music does anyway.
My first thought is that we need to rethink this process. Assuming you're using RESTful controllers, it's unclear to me why you would need a Music controller and a Song controller... how are those resources different? The next relevant question would be, why is it not sufficient to show errors via Song#create ? I mean, they couldn't get it right when it was just a form, is the distraction of additional content likely to help? :)
With that said, here is a possible solution. (Given that you didn't paste your code, I'm making a lot of assumptions here.)
<hack>
first, extract the form parts from songs/new to songs/_form, then from the music/index view, render :partial => songs/_form, and in the songs controller, render :action => '../music/index' (this is called a hackity-hack.) Because it's a hack, you will almost certainly need to go into music#index and add #song = Song.new
</hack>
If you start running on edge, the ability to pass a flash through a redirect was just added...but that doesn't really get you there.
The simplest solution though, is that you need to render index, but set up all of the variables that are needed for that page. If you factor that out into a separate module or method, you can call it from both the index action and the save failure.
def index
setup_for_index
end
def create
#song = Song.new(params[:song])
#song.save
#...
#on failure
setup_for_index
render :controller => "music", :action => "index"
end
def setup_for_index
#songs = Song.all
#etc
end
The other thing you could do is use form_remote_for and have the song form just update the div on failure. Then use an RJS template return type reload the whole song list on success.
While I want to reiterate what others have stated about your resource architecture deserving a second look, you can certainly render views for other resources using the :template option:
render template: 'music/index'
Why not a simple if request.post? conditional in the index action's view rather than redirecting to another page?
You can also try using flash[:song_save_error] to pass the error conditions back to your Music controller.
http://api.rubyonrails.org/classes/ActionController/Flash.html
You could try render :file => ...

Resources