Button call controller method, display results - ruby-on-rails

I have resources
User #from devise
Stream
Subscription
In my routes.rb file I have subscriptions as a nested resource to users.
resources :users do
resources :subscriptions
end
In Stream#show view I have a button that should save the #stream.title to #subscription.title.
<%= button_to "Subscribe", subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>
In my Subscriptions Controller
def create
#stream = Stream.friendly.find(params[:stream_id])
#subscription = current_user.subscriptions.create(subscription_params)
#subscription.title = #stream.title
#subscription.save
respond_to do |format|
if #subscription.save
format.html { redirect_to #subscription, notice: 'Subscription was successfully created.' }
format.json { render :show, status: :created, location: #subscription }
else
format.html { render :new }
format.json { render json: #subscription.errors, status: :unprocessable_entity }
end
end
end
Rake route
POST /users/:user_id/subscriptions(.:format) subscriptions#create
And in my Stream#index view I want to display the #subscription.title ' s
<tbody>
<% for subscription in #subscriptions %>
<tr>
<td><%= subscription.title %></td>
</tr>
<% end %>
And in my Streams Controller
def index
#streams = Stream.search(params)
#subscriptions = current_user.subscriptions.build(subscription_params)
end
I have added a reference index for each subscription to a user
class AddIndexes < ActiveRecord::Migration
def change
add_reference :subscriptions, :user, index: true
end
end
I am recieving a NoMethodError in Streams#show, undefined method 'subscriptions_path'.
And a NameError in StreamsController#index, undefined local variable or method 'subscription_params'

You get undefined method subscriptions_path because rails translates your format.html { redirect_to #subscription, notice: 'Subscription was successfully created.' } wrong. Change your #subscription into a proper helper path call. If you're not sure what you should provide here, you may want to run rake routes > routes.txt in the shell and find your subscriptions route definition there and call it with _path
You get undefined method subscription_params because most probably you haven't defined subscription_params anywhere. You most prolly want to access your subscription params like params[:subscription]. As for the proper key when it comes to accessing the params hash, it all depends how you build your form in a view.

<%= button_to "Subscribe", subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>
The resource above doesnt exists, you have only defined a nested resource subscriptions inside users.
So you should have something like this instead, using the nested resource user_subscriptions_path.
<%= button_to "Subscribe", user_subscriptions_path(#subscription), :class => "button", :method => :post , :remote=>true %>

Related

"undefined method `each' for nil:NilClass" only after new user creation. Strange behavior

undefined method `each' for nil:NilClass:
<% #users.each do |user| %>
Admins in my app can create users manually through a user dashboard that I created. However, after clicking the button to create a new user, some strange things happen.
First, I am presented with "undefined method 'each' for nil:NilClass", with a reference to the Users Index View (which is where admins are redirected after user creation. If I refresh the page, the browsers URL box still states that it's on the Users Index page, however, the screen displays the New User page with statement saying that the entered User Email is already taken. If I manually go to the User Index page, then I can see the User added successfully, and I am NOT presented with the undefined method error. What the heck! I know I have some messy code, but I have no idea why this is happening.
Users Controller Excerpt:
def index
#users = User.all
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { render :index, notice: 'user was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
Users Index View Excerpt:
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.admin ? "<i style='color:green' class='glyphicon glyphicon-flash'><strong>Admin</strong></i>".html_safe : " " %></td>
<td><strong><%= link_to user.email,user %></strong></td>
<td><span class="badge"><%= user.sign_in_count %></span></td>
<td><%= user.activated ? "<i style='color:green' class='glyphicon glyphicon-ok'></i>".html_safe : "<i style='color:red' class='glyphicon glyphicon-remove'></i>".html_safe %></td>
<td><b>
<%= link_to user do %>
<span class="badge"><%= user.apps.count %></span> View
<% end %>
</b></td>
<td><%= link_to "<i class='glyphicon glyphicon-pencil'><strong> Manage</strong></i>".html_safe, edit_user_path(user), class: 'btn btn-primary btn-xs' %></td>
<td><%= link_to "<i class='glyphicon glyphicon-remove'></i> Destroy".html_safe, user, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-xs' %>
</td>
</tr>
<% end %>
</tbody>
Routes File Excerpt:
devise_for :users, :path_prefix => 'u'
resources :users
devise_scope :user do
get "login", to: "devise/sessions#new", as: :login
get 'logout', to: 'devise/sessions#destroy', as: :logout
get 'user/edit', to: 'devise/registrations#edit', as: :change_password
end
Let me know if you'd like any additional code. You can find the entire app on GitHub here:
https://github.com/nickdb93/QwesteraCONNECT/tree/completion
Your solution is perfect:
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'user was successfully created.' }
This works because you changed render to redirect_to. Render will render a view with the instance variables it has access to in that action. In your original problem, you called render in the #create action. This didn't work because the #create action doesn't have access to the #users instance variable.
redirect_to tells the browser to re-request a new url. In your working solution, you are telling the browser to request the url that goes to the #index action. The index action will then set the #users instance variable and render :index
These resources explain the difference between render and redirect_to better than I ever could:
Are redirect_to and render exchangeable?
Render and Redirect
I probably didn't solve this the best way, but I found a convenient workaround.
I changed the if #user.save action in my UsersController#create as follows.
respond_to do |format|
if #user.save
format.html { render :index, notice: 'user was successfully created.' }
was changed to:
respond_to do |format|
if #user.save
format.html { redirect_to users_path, notice: 'user was successfully created.' }
Please add your input if you have a better way. I'd love to learn the Rails way to do this.

Updating database Model view controller rails 4 method

I want to call a method that updates an attribute when saved.
Here is my index.html.erb
<% #users.each do |user| %>
<div>
<strong><%= user.email %></strong>
</div>
<% if can? :update, User %>
<%= link_to 'Make Author', User, method: :add_roles %>
<% end %>
Below is my user_controller.rb
def add_roles
respond_to do |format|
if #user.update(user_params)
user.author = true
user.save!
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
It doesn't update the attribute though. I think it is because I am not properly attaching it to the correct user. I want to current_user to update another user.
I think the solution is simple, first do what avlazarov said in his comment:
In the view <%= link_to 'Make Author', "/users/#{user.id}/add_roles",
method: :patch %> In the routes.rb patch '/users/:id/add_roles' =>
'user#add_roles'
Or something simpler, in routes.rb:
resources :users do
patch :add_roles, on: :member
end
then in view:
<%= link_to 'Make author', add_roles_users_path(user) %>
Then rename user_controller.rb placed in app/controllers to users_controller.rb and make sure the class name is UsersController.

Simple one model singular resource routing problem

I have a stripped down shopping cart application, currently with one model "cart", the cart id is stored in a session.
the cart controller has this method so we always have a cart
def initialize_cart
if session[:cart_id]
#cart = Cart.find(session[:cart_id])
else
#cart = Cart.create
session[:cart_id] = #cart.id
end
end
my routes file has this one line
map.resource :cart
my cart/show view looks like this, i have added a form to it so that ultimately i can update the quantity of items, but for now i am just editing the created_at attribute.
<% form_for(#cart) do |f| %>
<%= f.date_select :created_at %>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
<%= link_to 'Edit', edit_cart_path(#cart) %> |
<%= link_to 'Back', cart_path %>
and finally, my update action looks like this:
def update
##cart = Cart.find(params[:id])
respond_to do |format|
if #cart.update_attributes(params[:cart])
format.html { redirect_to(cart_path) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #cart.errors, :status => :unprocessable_entity }
end
end
end
when i make a change to "created_at" attribute on the "show" page, the attribute is successfully updated, but when i get redirected, i get a bizare url like this
http://192.168.0.10:3000/cart.%23%3Ccart:0x23d46fc%3E
I have fiddled with the update action, and can get the whole thing to work perfectly by doing this
# PUT /carts/1
# PUT /carts/1.xml
def update
##cart = Cart.find(params[:id])
#respond_to do |format|
if #cart.update_attributes(params[:cart])
redirect_to(cart_path)
# head :ok
#else
# render :action => "edit"
# render :xml => #cart.errors, :status => :unprocessable_entity }
end
#end
Its something to do with the respond_to block that is causing it to mess up, i would really appreciate any help i can get with this.
Thanks
For singular resource, you don't need to specify the object in the routes.
So you should use this:
<%= link_to 'Edit', edit_cart_path %>
===== UPDATED =====
I just found your real problem ^^" (but the original should be true too)
You used form_for(#cart) do |f|, which produced that ugly path
Please change to form_for(#cart, :url => cart_path) do |f|
I don't know why too, but it should be ok......

link_to :action => 'create' going to index rather than 'create'

I am building a fairly simple recipe app to learn RoR, and I am attempting to allow a user to save a recipe by clicking a link rather than through a form, so I am connecting the user_recipe controllers 'create' function through a link_to.
Unfortunately, for some reason the link_to is calling the index function rather than the create.
I've written the link_to as
<%= "save this recipe", :action => 'create', :recipe_id => #recipe %>
this link is on the user_recipes/index.html.erb and is calling the 'create' function of the same controller. It doesn't seem to make a difference if I include the :controller or not.
The controllers look like this
def index
#recipe = params[:recipe_id]
#user_recipes = UserRecipes.all # change to find when more than one user in db
respond_to do |format|
format.html #index.html.erb
format.xml { render :xml => #recipes }
end
end
def create
#user_recipe = UserRecipe.new
#user_recipe.recipe_id = params[:recipe_id]
#user_recipe.user_id = current_user
respond_to do |format|
if #menu_recipe.save
format.html { redirect_to(r, :notice => 'Menu was successfully created.') }
format.xml { render :xml => #menu, :status => :created, :location => #menu }
else
format.html { render :action => "new" }
format.xml { render :xml => #menu.errors, :status => :unprocessable_entity }
end
end
In the standard REST scheme the index action and the create action both have the same url (/recipes) and only differ in that index is accessed using GET and create is accessed using POST. So link_to :action => :create will simply generate a link to /recipes which will cause the browser to perform a GET request for /recipes when clicked and thus invoke the index action.
To invoke the create action use link_to {:action => :create}, :method => :post, telling link_to explicitly that you want a post request, or use a form with a submit button rather than a link.
Assuming you have default resources set up in your routes file, i.e. something like this
resources :recipes
The following will generate a link that will create a recipe; i.e. will be routed to the create action.
<%= link_to "Create Recipe", recipes_path, :method => :post %>
For this to work, JS needs to be enabled in your browser.
The following will generate a link that will show all recipes; i.e. will be routed to the index action.
<%= link_to "All Recipes", recipes_path %>
This assumes the default which is a Get HTTP request.

Rails does not display error messages on a form in a custom method

I've created a custom method called checkout in my app. I create an order (which is done my adding products to my "cart"), assign it to my client, and then I head to my checkout screen where I confirm the items and enter their customer order number and complete the order (submit).
Everything works great except that it doesn't display error messages. I'm able to display a flash error notice (seen in complete_order method) when things go wrong but it doesn't specify the details like a normal form would. The error messages should appear if the customer order number is not unique for that client.
Below is the custom method (checkout) related code.
Order Model:
validates_uniqueness_of :customer_order_number, :scope => :client_id
Orders_controller:
def checkout
#order = current_order
end
def complete_order
#order = current_order
respond_to do |format|
if #order.update_attributes(params[:order])
#order.complete #sets submitted datetime and state to 'complete'
flash[:notice] = 'Thank you! Your order is being processed.'
format.html { redirect_to( products_path ) }
format.xml { head :ok }
else
flash[:error] = 'Please review your items' #added to confirm an error is present
format.html { redirect_to( checkout_path ) }
format.xml { render :xml => #order.errors, :status => :unprocessable_entity }
end
end
end
And the form in the checkout view:
<% form_for #order, :url => { :controller => "orders", :action => "complete_order" } do |f| %>
<%= f.error_messages %>
<%= f.text_field :customer_order_number, :label => "Purchase Order Number" %>
<p>
<%= f.submit 'Complete Order', :confirm => 'Are you sure?' %> <small> or <%= link_to 'cancel', current_cart_path %></small>
</p>
<% end %>
Any idea how I can display the specific error messages?
Change redirect_to to render in else condition otherwise checkout method get called again & no error will displayed.
else
format.html { render :action => 'checkout' }

Resources