Rails Wicked Gem - Understanding routing - ruby-on-rails

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.

Related

How to fit a form into a rails show after another form? Multiple same forms

I am making this form for a reply function in a blog-like app with the same recipe as the comment in which it should nest. (Comment recipe)
I get the following error when I try to view my app in the browser:
No route matches {:action=>"index", :post_id=>"10", :controller=>"replies", :comment_id=>nil} missing required keys: [:comment_id]
This is my reply view file for my replies/_form.html.haml
%h5 Reply
= form_for [ #post, #comment, #reply ] do |f|
%p
= f.label :name
%br
= f.text_field :name
%p
= f.label :talk
%br
= f.text_area :talk
%p
= f.submit 'Submit'
This is my replies controller getting a hold on the comments_id much like the recipe said I should do between the comments and the post_id:
class RepliesController < ApplicationController
def create
#reply = Reply.new(reply_params)
#reply.comment_id = params[:comment_id]
#reply.save
redirect_to post_path(#reply.comment.post)
end
end
And this is my id passing in the comments show controller as it is similar in the post show controller. Or should I add something more to the post show controller now?
def show
#reply = Reply.new
#reply.comment_id = #comment.id
end
I tried adding replies though the rails console. They show up neatly, so I think my routes file works. Something with the id's and the handling of the collections isn't going great though. The form part is not working.
I don't like adding gems if I don't have to, I want to understand my app.
EDIT: I should probably add that my app has a view that looks like a indexing-form system in a indexing-form system.
Below the post there are comments - with a form, and below these there are replies - with a form.
EDIT 2: First argument in form cannot contain nil or be empty is what I get now al the time.
EDIT 3: I still can't make my forms under the comments. This is my routes file, maybe it clarifies.
resources :posts do
resources :comments do
resources :replies do
end
end
end
I am debugging now by making print outs and found out that in my _form haml file for a reply rails can find the #post, but not the comment nor replies (but they have to be created of course with the form), while I can get almost exactly the same structure to work in my _form for a comment.
Is it even possible in Rails to have multiple forms printed out on the same page?
Still all help is appreciated!
EDIT 4: I have gotten a little further. Now Rails says:
No route matches {:action=>"index", :post_id=>"2", :controller=>"replies", :comment_id=>nil} missing required keys: [:comment_id]
As a direct effect of changing my show action in the post controller:
def show
#post = Post.find(params[:id])
## create a blank comment
#comment = Phase.new
#comment.post_id = #post.id
##
## The same for a blank reply
#reply = Reply.new
#reply.comment_id = #comment.id
##
end
The last line of this action seems to not make any difference. Now I just need to be able to grab this comment_id in the reply form and then I am done. Nearly a week of struggle.
I believe you may not be getting a #comment.id because you are doing Comment.new(reply_params) and objects only get id fields whens you use .create OR .save after instantiating with new. Let me know if this helps!
Because of this you are getting the nil error for #comment in the form.
EDIT
It seems like you are looking to get the comment_id from the form, another solution would be to get it from the URL by having this happen under comments path. You'd have to nest your resources so it's something like comments/:id/reply/:reply_id or comments/:id/reply/new.
Here's some great examples for nested attributes: http://guides.rubyonrails.org/routing.html#nested-resources
SECOND EDIT
Okay, I was a bit confused because typically you would have the form in new not in show. Either way I would be looking at the instance variables being passed in. How do your associations look?
if it's Post has_many :comments and Comment has_many :replies, then you can do something like this in your show actions:
def new
#post = Post.find(params[:post_id]
#comment = #post.comments.find(params[:comment_id]) #scopes your search to only the comments belonging to this post
#reply = #comment.replies.new
end
The more important point to get out of this is that each instance variable needs to be passed in. that being said, I'm not sure which ones are currently working for you
As far as create you should be doing something similar, creating through the associations. This rails magic handles all the foreign keys and assigning the id's etc:
def create
#post = Post.find(params[:post_id]
#comment = Comment.find(params[:comment_id])
#reply = #comment.replies.new(reply_params)
if #reply.save
# some logic
redirect_to wherever_path
else
# other logic
render :new
end
end
The more important point to get out of this is that each instance variable needs to be passed in. that being said, I'm not sure which ones are currently working for you
Let me know how this works!

rails3 show not getting :user_id in one case

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..

undefined method ..._index_path Ruby on Rails

I am trying to get a basic form to work and am struggling because I keep getting the error
undefined method `profiles_index_path' for #<#<Class:0x4fe1ba8>:0x4fccda0>
I have checked through and can't seem to work out where I am going wrong.
In my view (new.html.erb) I have:
<%= form_for #profile do |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>
<%= f.text_field :country %>
<%= f.text_field :about %>
<%= f.submit "Create Profile" %>
<% end %>
In my profiles controller I have:
class ProfilesController < ApplicationController
def new
#title = "New Profile"
#profile = Profiles.new
end
def create
#user = current_user
#profile = #user.profiles.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => "Welcome to your new profile!"
else
render "profiles#new"
end
end
def edit
#user = current_user
#profile = #user.profiles.find(params[:id])
end
def update
#title = "Update Profile"
#user = current_user
#profile = #user.profiles.find(params[:id])
if #profile.update_attributes(params[:profile])
redirect_to profile_path
else
render action: "edit"
end
end
def index
#user = current_user
#profile = #user.profiles.all
#title = "Profile"
end
end
And finally in my profiles model I have
class Profiles < ActiveRecord::Base
belongs_to :user
end
Any help people can offer really would be much appreciated because I am stumped. :)
Sorry forgot to include routes:
controller :profiles do
get "newprofile" => "profiles#new"
get "updateprofile" => "profiles#update"
get "profile" => "profiles#home"
end
resources :profiles, :controller => 'profiles'
The problem is indeed the way you've pluralized your model name. Don't do that. It should be a Profile, not a Profiles. There my be some work around to allow you to use a plural model name, but the answer is to stick to Rails convention rather than fighting the framework. Rename your model to Profile and the url_for helpers will understand how to correctly turn a new Profile object into a /profiles URL.
If you run "rake routes" command, do "profiles_index" appear in your routes? Usually for the index page of a model, the work 'index' is left out so the route is profiles_path
You error probably comes from a view where you've used profiles_index_path instead of profiles_path
I think it's failing due to the convention not being followed with your model name.
So I think you're problem is mostly around that you aren't following the convention on the model name, which would classically be singular, since each instance represents one profile. I think the form_for helper is trying to figure out what to do with it and failing as a result. So you have two options to try and resolve. Refactor the model name to singular (I'm not clear exacly how difficult that would be) or pass the :url paramater to form_for so it knows where to post to.
<% form_for #profile, :url => path_to_create_action do |f| %>
more information here:
I'm working with Rails 5 and I got the same error and it was specific using the word Media as my model and RoR used Medium as the plural so I got different routes when executing rake routes.
What I did to fix it was:
Delete the model I just have created.
rails d scaffold Media
Edit config/initializers/inflections.rb with:
ActiveSupport::Inflector.inflections(:en) do |inflect|
# Here you can put the singular and plural form you expect
inflect.irregular 'media', 'medias'
end
Now execute the scaffold again:
rails g scaffold Media
Now you must have everything in the way you expected. Because you have overwritten the Pluralizations and Singularizations (Inflections) in Ruby on Rails.
I hope it could be useful.
Have you tried to replace your form_for tag with the following?
<%= form_for #profile, :as => :post do |f| %>
It looks like it's trying to treat it as a GET request to "/profile". And, since it is not finding the index action, it craps out. I think forcing it to do a POST will fix this issue.

form_tag action not working in rails

I have this form in my application.html.erb.
<%= form_tag(:action=>"index", :controller=>"posts") %>
<p>
// code here
</p>
I dont understand why is this getting directed to posts->create instead of posts->index?
Thanks.
Basically, Rails observes and obeys "RESTful" web service architecture. With REST and Rails, there are seven different ways to interact with a server regarding a resource. With your current code, specifying the form's action as index doesn't make sense: Rails' form helpers can either POST, PUT or DELETE.
If you wanted to create a post, then redirect to the index, you can do so in the applicable controller action:
class PostsController < ApplicationController
...
def create
#post = Post.new
respond_to do |format|
if #post.save
format.html { redirect_to(:action => 'index') }
end
end
While your form would look like:
<% form_for #post do |f| %>
# put whatever fields necessary to create the post here
<% end %>
You seem to be a little mixed up with respect to the uses for each action. Here's a quick summary of typical RESTful usage:
Index -> view a list of items
New/Edit -> form where items are added or edited
Create/update -> controller action where items are created/updated
The reason your routes file is not taking you to index is because index is not an action where posts are typically created or updated. The best way is to go RESTful. Unless you have a very unusual situation, the best way to set your system up is probably a little like this:
# routes.rb
resources :posts
# application.html.erb (or better: posts/_form.html.erb).
<% form_for #post do |f| %>
<% end %>
# posts controller, whichever action you want to use
def new
#post = Post.new
end
By putting the form in a partial called form you can access it in new, edit, or wherever else you need to manipulate a post in your system.

Rails RESTful controller and rendering after custom action

How can I render after executing an action in a restful controller instead of redirecting.
I have a controller with standard actions, and I added a special action that adds data to the resource in question, via a form on the #show page (Think comments on a post). I am validating the input from the form and want to re-render the show action on error and redirect to the show action on success.
I want to render to save the user from inputting their info twice, but when I try to render the show action with an error in the flash[:notice] I get an error saying that I am not specifying an ID. When I do specify an ID, it tries to render a new template that doesn't exist yet.
I am thinking that it should be a as simple as:
def add_comment
if my_validation?
save the object
redirect_to :action => "show", :id => params[:id]
else
render :action => "show", :id => params[:id]
end
end
This is not my actual code, just something I put together just now as an example.
The best way is to re-render the :new
def create
#obj = TheObject.new(params[:object])
render :action => :new unless #obj.save
end
And in the new.html.erb
<% form_for :obj,
:url => object_url(#obj), :html => {:method => :post} do |f| %>
<%= f.text_field :name %>
<% end %>
That way, the inputs in the form will be pre-filled with what the user entered.
Create a new data object and add the values from the form, before you rerender, think it would work then. If you still get problems, try setting a boolean for editing new vs. existing rows, or create two different views entirely.
I've done it before but I don't quite remember how. Sometimes when I used the very typical use of the MVC pattern, it was allmost "automagical", othertimes (as I had to use an old quirky database) I had to code all the magic myself; sometimes usin the .new? function (or what it was called) on the ActiveRecord object, othertimes I used temporary "magic values" for ID (typically alphabetic strings for invalid id values.
(I appologize if I made some mistakes, it's a while since I coded Rails code...)

Resources