form_for error in rails 3 - ruby-on-rails-3

I am trying to save a model named 'customer' using form_for tag. I do not have a controller for this model, i was hoping to use another controller 'public' for this task. So here is my view:
<%= form_for #customer do |f| %>
<div class="field">
<%= f.label :name %><br/>
<%= f.text_field :name %>
</div>
.... and then
<%= f.submit 'Order', :action => :save_order %><br/>
and here is my controller
def check_out
#customer = Customer.new
end
def save_order
#customer = Customer.new(params[:customer])
credit_card_no = #customer.credit_card
#order = Order.new
#order.line_items << #cart.items
#customer.orders << #order
if #customer.save
# process credit card
#cart = nil
redirect_to(:action => :show_bill, :id => #order.id)
else
flash[:notice] = 'Could not process your credit card information'
render(:action => :check_out)
end
end
The view is loaded from action 'check_out' and it was supposed to go to action 'save_order' but i am getting an error in view for 'form_for' code, what am i doing wrong ? But if i create a controller or scaffold for 'customer' and try to use that, i get redirected to 'customer/show/:id' path, and i dont want that.

If you want to use different controller with form_for you need to use :url option in form_for.
<%= form_for #customer, :url => { :controller => "your controller name",
:action => "save_order" } do |f| %>
#your code
<% end %>

Sorry, but you are asking for help in how to make something work while doing it wrong. I will try to explain and I hope this will help you.
If you want to save a customer model you should use, guess what, a customers controller. Some people like to use scaffolds, some people hate them. But the fact that the scaffold code redirects to the show method after saving a model, which is easily changed, shouldn't stop you from using it. The scaffold is just there to help beginners and/or to have a way to come up with something quick and dirty. Changing the scaffold generated code here and there is not only usually necessary it's a good way to learn.
To save an order you should use, ::drumroll::, an orders controller. I don't even know what a "public" controller would do (which by itself should tell you at least that it is poorly named).
I suggest you get the Agile Web Development with Rails book and go through the depot application. It covers all of this very subject well and you will learn a lot.

Related

Rails: No route matches [PUT] "/blog/2"

I am creating blog application in rails. I have a common form for creating and updating blog.
This is view of edit and new.html.erb
<%= render :partial => "form"%>
This is view of _form.html.erb blog:
<%= form_for #blog do |f| %>
<%= f.text_field :title, :placeholder => "Title" %><br>
<%= f.cktext_area :article, :placeholder => "Content", :ckeditor => {:toolbar => "MyToolbar"} %>
<%= f.submit %>
<% end %>
My blog is creating successfully but I am getting error on update action. This is my edit and update action in blog controller:
def edit
#blog = Blog.find_by_slug(params[:id])
end
def update
#blog = Blog.find(params[:id]) || not_found
#blog.update_attributes(params[:blog])
redirect_to "/blogs/#{#blog.slug}"
end
When I open form from edit view, and click on update button, it throws error:
No route matches [PUT] "/blog/2"
My routes.rb is:
resources :blogs
get 'blog', to: 'blogs#index'
get '/blog/:id', to: 'blogs#show', as: 'blog'
I am not getting where it is going wrong. I tried to add "url: blogs_path" in form_for, it removes the error but doesn't save the edit changes.
Can anybody help me where I am going wrong here?
Thank you.
Okay. I dont understand why you want to go against conventions. Anyway, using form_for resource would automatically generate action URL as a PUT to /resources/:id if its an update operation.
So to override this you need to do two things.
update your routes to support this:
Add this line to your routes file:
put 'blog/:id' => 'blogs#update', :as => 'update_blog'
It is important that you put this line above your 'resources :blogs` call.
2 . specify the URL to which the form should submit:
You will need to create the form tag like this:
<%= form_for #blog, :url => update_blog_path(#blog) do |f| %>
Try this and let us know.

In Rails 3 how does the simple_form_for method know whether to include the params[:id] in the action attribute?

I'm new to rails, and I'm trying to figure out how to make the [action] attribute on a form dynamic so that I can reuse the form markup.
In MVC.net it's easy as you usually specify the :controller and :action.
However in rails there's just a "simple_form_for(#my_model)" method.
If I browse to /my_models/new the action attribute is:
action = "/my_models"
But if I go to /my_models/1/edit the action attribute is:
action = "my_models/1"
What if I want to create a new action for handling POSTs of my_model AND still reuse the same _form.html.erb... how does that work?
I think it's actually rails doing this
https://github.com/rails/rails/blob/master/actionpack/lib/action_view/helpers/form_helper.rb#L230
In short it just infers the url based on the resource and whether it is new or an existing one.
SimpleForm's FormBuilder is inherited from ActionView::Helpers::FormBuilder
You can check out that code https://github.com/plataformatec/simple_form/blob/master/lib/simple_form/form_builder.rb
I guess I'm not understanding the last part. Say you wanted to use a custom action instead of the inferred ones you could just make a partial of the form elements and use that partial for all forms.
so _form.html.erb
<%= simple_form_for #my_object do |f| %>
<%= render 'form_elements' %>
<% end %>
_custom_form.html.erb
<%= simple_form_for #my_object, :url => custom_url do |f| %>
<%= render 'form_elements' %>
<% end %>
_form_elements.html.erb
form elements as usual

Rails 3.2 One to Many View

I have tried to get this working, looked at multiple tutorials, questions on here tried different things for about a week now and I can't get the view to work correctly.
I have teams of users. A team has_many users and a user belongs_to a team (one team at a time). I know the association works because I got it working using the console (with some help there). I'm not sure how to get it working in the view. Below is the code, please let me know if more is needed.
What am I missing?
_join_team_button
<%= form_for(#user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Team Show Page
<%= render 'shared/join_team_button %>
Teams Controller
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
Users Controller
def show
#user = User.find(params[:id])
#teams = #user.team
end
I tried to put a complete demonstration of what you are looking for. Let me know if it fits for you.
#FILE: models/team.rb
class Team < AR::Base
has_many :users
end
#FILE: models/user.rb
class User < AR::Base
belongs_to :team
end
#FILE: config/routes.rb
#Here you are defining "users" as a nested resource of "teams"
resources :teams do
resources :users do
member do
put :join
end
end
end
#if you run "rake routes" it will show you the following line along with others
join_team_user PUT /teams/:team_id/users/:id/join(.:format) users#join
#FILE: controllers/team_controller.rb
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
#FILE: views/teams/show.html.erb
<% if(#user) %>
<%= form_for #user, :url => join_team_user_path(#team, #user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
#You dont really need a form for this. You can simply use `link_to` like below
<%= link_to 'Join', join_team_user_path(#team, #user), method: :put %>
#FILE: controllers/users_controller.rb
def join
# params[:id] => is the user_id
#user = User.find(params[:id])
# params[:team_id] => is the team_id
#team = Team.find(params[:team_id])
# Now make the relationship between user and team here.
#user.update_attribute(:team, #team)
end
Update:Based on your comment
Q: Do I create a new user's resource and nest that or do I nest the already establishes user's resource?
Ans: Based on your requirements any resource can be defined both independently or nestedly. But yes you can control that which method will be available in which way. Like in your case, you can allow only join method when your user is nested under team resource.
resources :users, :only=>:join do
member do
put :join
end
end
resource :users
run rake routes with and without :only=>:join option and see differences in available routes.
Q: Will that affect other things?
Ans: If you strictly define your routes following above example, it should not affect other things. You should confirm all the available routes to your application by rake routes.
Q: Should I put my current routes.rb file up there?
Ans: Assuming your current routes.rb will be modified in the above way. Could I answer the question?
Q: Confused about the comments controller?
Ans: Im extreamely sorry. Yes it must be users_controller.rb as the rake routes command is showing. Result of copy and paste from my own example code :P
Q: what should I put there? the build method
Ans: In your case both the user and team is already exists in your database. All you need to do is just setup a relationship. So you can just use update_attribute option. Ive changed the join method. Please check. But yes if want to create new entries you might need build methods.
Sorry for the late reply :)
I figured it out. Still not perfect, but it gets the association working. The team, and the user were already created, I just needed to establish the association, so the build method would not have worked. Here's what I have:
View:
<%= form_for(#user) do |f| %>
<%= f.hidden_field :team_id, :value => #team.id %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Teams Controller:
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = User.find(params[:id]) if signed_in?
end

Issues getting a profile to update and show newly submitted form item

Following up on a previous question, I have a few issues to resolve before I have a comment form showing and submitting securely on my profile. I'm a beginner to programming so thinking across multiple controllers seems to have me lost.
What I'm doing is posting comments in a form, then listing them.
Background: The _comment_form and _comment reside as partials in the Profile about. (My next task is toggling from about to other Profile information, but that's another question altogether.)
Using the help provided in my last question I feel like I'm almost there but am getting an error.
CreateComments migration:
t.integer :profile_id
t.integer :author_id
t.string :body
My Comment model:
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :author, :class_name =>"User", :foreign_key => "author_id"
end
CommentsController:
def create
#comment = Comment.new(params[:comment].merge(:author_id => current_user.id))
#comment.save!
redirect_to profile_path(#comment.profile)
end
ProfilesController:
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
render :action => 'new'
end
end
def show
#user = User.find(params[:id])
#profile = #user.profile
#comment = #profile.comments.new
end
Comment partials inside Profile partial:
<div id="commentEntry">
<%= render :partial => 'comment', :collection => #profile.comments %>
</div>
<div id="newitem">
<%= render :partial => 'comment_form' %>
</div>
Routes.rb:
resources :users do
resources :profiles
end
resources :comments
_comment_form.html.erb:
<%= form_for #comment do |f| %>
<%= f.text_field :body %>
<%= f.submit 'Add new' %>
<% end %>
_comment.html.erb:
<li class="comment" title="<%= #comment.author.profile.first_name %> <%= #comment.author.profile.last_name %>">
<%= #comment.body %>
</li>
So, Issue #1: Wrapping the _comment.html.erb in a loop <% for #comment in #user.profile.comments %> shows the profile but when I try and submit a new comment I get "Unknown action The action 'update' could not be found for CommentsController". If I take away the loop, the profile doesn't show and I get "NoMethodError in Profiles#show undefined method `profile' for nil:NilClass". Can anyone help me out and explain what I'm doing wrong?
Issue #2: I created a sample comment in rails console and when I get the profile to show, the input field for comment :body repopulates with the comment's body. Any ideas on what could be going on?
Short explanation of your problem:
The #comment you're getting in your _comment_form partial is one that's already saved in your database, hence the call to the update action and the body that's already filled.
You're creating the new comment just fine with #comment = #profile.comments.new in your show action, but it gets overridden somewhere else.
You're mentioning that you wrapped the _comment render in a loop with <% for #comment in #user.profile.comments %>, the problem is most likely there.
Fix:
The only thing you should have to change is the _comment partial to (without the for loop that you added):
<li class="comment" title="<%= comment.author.profile.first_name %> <%= comment.author.profile.last_name %>">
<%= comment.body %>
</li>
When you do the render :partial => 'comment', :collection => #profile.comments, rails is smart enough to loop over #profile.comments and give the comment (not #comment) variable to the partial.
How to avoid this the next time:
I'll give you two rules of thumb to avoid getting in this situation:
Try to name your variables more precisely. #new_comment would have been a better name for the variable to store the new comment. #comment is a bit ambigous as you've got a boatload of those in your view.
Avoid creating and modifying instance variables (# variables) in your views, try to do this only in your controller. I'll admit your particular case was a bit harder to detect because of the <% for #comment in #user.profile.comments %>. The view got its name for a good reason, it's only supposed to let you view the data you've defined in your controller.
Hope this helps.

Rails 3, Form submitting to its controller

I'm new to Rails and I've just spent another hour Googling and not finding an example.
So I have a simple form that I need to submit to an API. So I tried submitting it to the API directly but got advice that I do it in my app so I can do something with the results. Anyway, here's my simple form:
<%= form_tag(:action => 'submit') do |f| %>
<%= f.text_field :email, :value => "Your email address...", :class => "text", :id => "email", :name => 'email',
:onFocus => "change(this,'#222222'); this.value=''; this.onfocus=null;",
:size => "26" %>
<%= f.hidden_field :ref_code, :id => 'ref_code', :name => 'ref_code', :value => #referralid %>
<%= submit_tag "Enter To Win", :class => "button-positive submit" %>
<% end %>
Everything I'm seeing has forms that that use a model, I have no need to persist this data, just pass it on to the API.
So my thought was I just create an action in the home controller, where this page lives and have the action submit to it but I get a RoutingError and it's: No route matches {:action=>"submit", :controller=>"home"}
So what do I need to put in the Routes.rb? I tried:
namespace :home do
resources :submit
end
No Joy... I'm sure it's simple but I just can't find the right example.
I think that you should have a look at the ruby guides, it's very well explained (but I don't think it talks about API) and it will save you a lot of time in the future, I swear.
Not sure what you mean but I see some wired stuff, so I hope to be useful, but if you're following some tutorials from the net let us know the link.
Basically what I do is always to call an action of a controller (MVC), following this way you should have a controller (?? apis_controller ??) and call one action of it.
So you want to use form_tag instead of form_for because you're not addressing a model, therefor you want to get rid of f. and use suffix _tag (api).
<%= form_tag(send_api_path) do %>
<%= text_field_tag :email, "Your email address..." %>
<%= hidden_field_tag :ref_code, #referralid %>
<%= hidden_field_tag :api_name, 'your_api_name' %>
<%= submit_tag "Enter To Win" %>
<% end %>
Then, in your apis_controller.rb you create an action send where you send and manage your request.
#apis_controller.rb
def send
# TODO: your code here
end
Another thing is to set the routes, something like
#routes.rb
match 'apis/send' => 'apis#send', :as => :send_api
I'm sure this is not 100% working code, but it should be useful
How to call the api? I had I fast look and found this.
When you ask for help it's always good to attach the error you get, this makes it easier for people to understand the problem.