I have a strange problem. I've been coding in Rails for, off and on, a year. I created a new project recently and used scaffolding. Things were going fine, yesturday I started implementing some favoriting features. Now I have a strange problem. I rolled back the stuff I did last night but still have the problem. First
Entry belongs to user
User has many entries
My Entry show method in my controller is very standard and simple
def show
#user = User.find(params[:user_id])
#entry = #user.entries.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #entry }
end
end
When I view the entry from a normal link in the entries index
<%= link_to 'Show', user_entry_path(#user, entry) %>
I takes me to where it should go:
/users/4/entries/11
When I create new things still look good
/users/4/entries/new
Until I click "create entry" or the submit button
<div class="actions">
<%= f.submit %>
</div>
Then it goes to
/entries/20 ...with the error:
ActiveRecord::RecordNotFound in EntriesController#show
Couldn't find User without an ID
If I go back to the entries index however, the file new entry is there and the show link takes me to the right place. Thoughts? Your help is appreciated!
The error message tells you that User.find(params[:user_id]) couldn't find a user with that ID. Try checking the structure of the GET parameters in the server logs.
If your GET path is /entries/20, then the path only has an entry ID and is missing a user ID. You might be able to fix this in your Controller#create by having it redirect to user_entry_path instead of entry_path.
How does your form look like?
I think you have nested routes? Your form should look like following:
<%= form_for [#user, #entry] do |f| %>
<% # your fields %>
<% end %>
Your form seems to point to resources entry, instead of the nested ressource..
Related
I am making an auction site and have been scratching my head trying to figure out how to best deal with auction/product creation. What I have come up with, and it may be a horrible idea, is to have a List Item link that, when clicked, posts to the create action for the auctions controller and then redirects to the edit page for that auction.
The reason I want to do this is because I feel it will make adding photos to the product at creation time easier and I can save the state of the auction so that they can come back and finish it later if they want.
The question:
How do I make a link post to the create action and then redirect to the edit page for the newly created item?
Let me know if there are any specific files you need to see, but I don't really have any code to go off of since I haven't made my create and edit actions yet or the routes
If you are using form_for in your view, you can change the destination url and set the method to post like this:
<%= form_for #auction, { :url => auction_path, :method => :post } do |f| %>
... Create your form ...
<% end %>
Then in the controller:
def create
#auction = Auction.new(params.require(:auction).permit(< list your parameters here>))
if #auction.valid?
#auction.save
flash[:notice] = 'New Auction created successfully.'
redirect_to 'edit'
else
render 'new'
end
end
Okay, so I'm not really understanding nested routing in the wicked gem.
So far I have this. I'm not sure if everything is in the right folder or if I'm doing that right.
routes.rb
resources :events
resources :events do
resources :build, controller: 'events/build'
end
controllers/events_controller.rb
def create
#event = Event.new(event_params)
if #event.save
flash[:success] = "Event Created!"
redirect_to event_build_path(event_id: "event", id: #event.id)
# previously had redirect_to event_build_path without parameters)
else
render 'new'
end
end
controllers/events/build_controller.rb
class Events::BuildController < ApplicationController
include Wicked::Wizard
steps :details, :visibility
def show
#event = Event.find(params[:event_id])
render_wizard
end
end
views/build/details.html.erb
<%= form_for #event do |f| %>
#blab blah
<% end %>
I had the event_build_path without parameters at first and I had this error
No route matches {:action=>"show", :controller=>"events/build"} missing required keys: [:event_id, :id]
Had influence from this Rails wicked gem redirect with params but don't entirely understand the routing
I don't have an event_id set and I don't really understand how wicked keeps track of the step of via the id (or if its event_id).
As my object (event) is not created yet, what is "event_id" and the id at the end represent?
Not really an answer, but some clarifications. The thing you're trying to do is pretty hard, and requires a bunch of customizations to suit your own case. If you're not comfortable with wicked, or if that tutorial is nearly incomprehensible, it might be better to skip doing a wizard for now and come back and try it again in a month or so once you've had time to meditate on it.
Form
This is your wicked form
<%= form_for #event do |f| %>
#blab blah
<% end %>
Wicked works by doing two things, storing state in your url domain.com/build_pah/<step> and providing you with helper methods to easily manipulate the current state. Once you render the form you need to tell the browser where to submit info to when enter is pressed. Right now it is going to #event path, which isn't what we want. Instead we need to do something like:
<%= form_for #event, :url => wizard_path, :method => :put do |f| %>
<% end %>
This tells the form to go to the wizard_path url, this is a helper we provide. It also tells the form to submit using the PUT HTTP method, which should trigger your def update action inside of your Events::BuildController if it is set up correctly. On another note it doesn't look like Events::BuildController has an update action.
Event Controller
Your event controller looks fine, however you're redirecting
redirect_to event_build_path(event_id: "event", id: #event.id)
Wicked needs the id parameter to be the step you want to go to. So it should be:
redirect_to event_build_path(event_id: #event.id, id: :details)
or
redirect_to event_build_path(event_id: #event.id, id: Wicked::FIRST_STEP)
You can also get fancy and redirect to the index action which will do another redirect to the first step, but i always prefer being explicit.
Other Questions
Here is someone with a similar question: https://github.com/schneems/wicked/issues/141 take a look at their code, and their question. Try to understand what was wrong and how it was fixed. Then compare between what they're trying to do and what you're trying to do.
This question
It's hard to be more helpful without an explicit question. Breaking it down into I did this => I expected this => I got this instead , I tried to debug using this . Anywhoo, hope some of this was helpful. Maybe spin up another Rails example app and try to walk through my wicked tutorial in the readme, it will give you some more experience with what wicked does (and doesn't) do for you.
I am struggling to pass an id successfully into my URL for the nested resource I have set up called Jobs.
The error I am getting when I try to pass the #job object into my link is as follows:
No route matches {:action=>"edit", :controller=>"jobs", :user_id=>1, :id=>nil}
Which clearly shows it can't find the id correctly and so is finding nil
At the moment I have my routes setup as so:
resources :users do
resources :jobs
end
and the link I have is <%= link_to "Edit", edit_user_job_path(#user.id,#job) %>
What is interesting is that if I pass the object #jobs with an 's' on the end it will load the page correctly but when I click on the link will try and add all of that users job id's.
In my controller for edit I have:
def edit
#user = current_user
#job = #user.jobs.find(params[:id])
end
Any help really would be much appreciated :)
UPDATE
Okay I was defining the object on the wrong page of my controller (under edit instead of index). The issue I am now having is Couldn't find Job without an ID
I updated my controller index definition to:
def index
#user = current_user
#jobs = #user.jobs.all
#job = #user.jobs.find(params[:id])
end
And have in my view (jobs#index)
<% #jobs.each do |f| %>
...
<%= link_to "Edit", edit_user_job_path(#user.id,job) %>
...
<% end %>
Any advice would be much appreciated if you know where I am going wrong :)
That error means that #job is nil.
The link is to the edit path, and the controller code you've provided is from the edit action in the controller. It seems unlikely that the edit page links to itself.
Look at the code that's actually rendering that page (it will appear in your stack trace) and you'll find that #job is not set. I suspect that you are on the index page and have something like:
<% #jobs.each do |job| %>
...
<%= link_to "Edit", edit_user_job_path(#user.id,#job) %>
...
<% end %>
If that is the case, then the link should be to job, not #job, i.e.
<%= link_to "Edit", edit_user_job_path(#user.id,job) %>
(expanding on iHiD's comment with his own post)
Using the restful resources means that you are going with the rails defaults, which consequently means that the index page gives you a list of all Jobs, and by default no single special job. If you run rake routes from the command line, you get all the routes, with parameters that are set from the URI. It should give you something like this:
user_jobs GET /users/:user_id/jobs(.:format) jobs#index
As you can see, there is no :id (params[:id]) for the index action.
on form submission to "create" action in the sexes_controller, I've changed things to actually redirect back to the page views/results/index that the form was submitted from, but now the flash message is not displaying even though I'm doing
<%= flash[:notice] %>
at the bottom of views/results/index (i.e. the page the form was submitted from), which is how I assume you're supposed to do it.
Is it because there's some sort of caching that's taking place that the flash message is not showing up? Any idea how to get around that?
Update
thinking it might be more complicated, I've tried to retrieve the flash message in the index action of the results controller
#flashbash = Sex.find(params[:id])
and then back in views/results/index
<%= if #flashbash flash[:notice] %> (I think this code is wonky)
note, I tried this, but it didn't work. It said, Couldn't find Sex without an ID
Any ideas how I can fix this?
Typically the flash is rendered in the application's layout file. This avoids the duplication of having to output <%= flash[:notice] %> in every view that could potentially have a flash message.
As to why its not showing up check that you are setting your flash[:notice] variable with something to display. An example of a create action in a controller may look like this:
# app/controllers/sex_controller.rb
def create
#sex = Sex.new(params[:sex])
if #sex.save
flash[:notice] = "Saved successfully"
redirect_to #sex # This redirects to the show action, where the flash will be displayed
else
flash[:error] = "There were errors..."
render :action => :new # This displays the new form again
end
end
# app/layouts/application.html.erb
<html>
...
<%= flash[:notice] %>
<%= flash[:error] %>
<%= yield %>
...
</html>
More information on flash messages here: http://guides.rubyonrails.org/action_controller_overview.html#the-flash
I have the following snippet of code in my controller
def create
#message = Message.new(params[:message])
#message.message = h(#message.message)
if #message.save
flash[:message] = "Message Sent. Thank You for Contacting Me"
else
flash[:message] = "OOps Something went wrong"
end
redirect_to :action => 'contact'
end
When I try to display the flash message in the contact form it doesnot display. I looked up possible solutions, but they dont seem to work. Any ideas what is going wrong?
Your controller is redirecting to :action => 'contact'. Ensure that the template being rendered for that action has the flash notice output.
<%= flash[:message] %>
Also, you may want to use render :action ... vs redirect_to :action .... Save yourself a request.
The flash hash can contain any set of messages you want to save until the next render. Scaffolds usually use the contents of flash[:notice] for notification messages. If you didn't use a scaffold to generate your web page you will have to add <%= flash[:notice]%> to your views.
You're setting flash[:message] in your controller. So it's not going to show up anywhere in your view unless your view contains <%= flash[:message]%> somewhere.
Your possible solutions are change all occurrences of flash[:message] to flash[:notice] in your controller or add <%= flash[:message]%> to any views that this action could render.
Not saying that you wouldn't have tried it, but if I were you I would do something down the lines like
<% if flash[:messsage].blank? %>
<h1> flash hash is blank </h1>
<% end %>
If you see the "flash hash is blank" in your browser you know what it means.
EDIT:-
Something from the docs "Just remember: They‘ll be gone by the time the next action has been performed." Try this in your controller
flash.keep(:message) #keep the flash entry available for the next action
I recently ran into a scenario where flash messages will not be preserved. This scenario is when submitting a form which does not contain the CSRF token field. Rails will not be able to verify the CSRF token, so it will not preserve the flash messages. If you are using a plain HTML form, use the form_tag helper to automatically add this field for you.
<%= form_tag '/example/url' do %>
<input name="example">
<input type="submit" value="Submit the Form">
<% end %>