How to create form that switches between instances of a model? - ruby-on-rails

I have a model, Product, and on the show view for this model, I want to have a select box for the user to be able to view a different Product. So, if a user's looking at the "Product 1" page, they can select "Product 2" from the select box and view that product.
Here's the code I'm using to create this select box:
<%= form_tag({:controller => "products", :action => "show"}, :method => :get) do %>
<%= select_tag :product_id, options_from_collection_for_select(Product.all, :id, :title) %>
<%= submit_tag 'Go' %>
But this doesn't work. I can choose a different product, and click Go, but it just goes to the same product, not the one I selected in the box.
What am I doing wrong here?
Basically, I'm trying to use a select box instead of something like this:
<% Product.all.each do |p| %>
<%= link_to p.title, p %>
<% end %>
Here's what I have for my show action in the controller:
#product = Product.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = 'The product you were looking for could not be found'
redirect_to products_path

well a simple way would be to check if the params[:product_id] was passed by your form, if it is then use that instead of params[:id] basically:
if params[:product_id]
#product = Product.find(params[:product_id])
else
#product = Product.find(params[:id])
end

If you can post your code on the ProductsController for Show, it would clarify things more.
The id you want to use for "showing" the right product is passed by params[:product_id]. So you should be using that in your ProductsController

Related

Why is my instance variable always Nil in my Rails view

The problem that I'm having is that any instance variables that I declare in my show function of Charges Controller, appears as nil in the view. If I set an instance variable to a number, it doesn't even appear in the view. My home function works perfectly with instance variables.
This is my Controller with the Home and Show functions:
class ChargesController < ApplicationController
def home
#products = Product.all
end
def show
#product = Product.find_by(id: params[:id])
end
This is my View for the Show function(show.html.erb):
<h1>Product Details</h1>
<h3> <%= #product.name %> </h3>
<h4> <%= #product.price %> </h4>
<h5> <%= #product.description %> </h5>
This is my view for the Home function that contains the button that directs to the show page(home.html.erb)
<h1>Products</h1>
<% #products.each do |product| %>
<br>
<p> <%= product.name %>: $<%= product.price %> </p>
<p> <%= product.description %> </p>
<%= button_to "Product Details", charge_path(product.id), :method => "get" %>
<br>
<%end%>
error message I'm receiving
find_by method returns nil if it does not find the record. So that means the product id(params[:id]) you searching in your Product model is not found.
You can check it manually in the rails console.
Type rails c in your terminal then try the bellow code
Product.find_by(id: the_id_you_want_to_search)
Alternatively you can use find method. It raises an exception when it does not find the record.
def show
#product = Product.find(params[:id])
end
By default ,its always find by id,So kindly use only..
def show
#product = Product.find params[:id]
end
Moreover,you can check in rails console using rails c to verify that the record is present with that id using,for example Product.find 18.
Also check the url which should match with your routes..for example../users/:id for get request Only mapped to users#show action.
Get local copy of your routes using rake routes > path.text and use it as reference
In your home.html.erb try change this
<%= button_to "Product Details", charge_path(product.id), :method => "get" %>
to
<%= link_to "Product Details", charge_path(product.id) %>
Then if it does not work, try to raise the params or the instance in your show method
def show
raise params.inspect
#product = Product.find params[:id]
end
or
def show
#product = Product.find params[:id]
raise #product.inspect
end
Those were some simple ways to check whats happening in your code.

Rails 4 checkbox not working, no changes in db

I have a big problem with checkboxes and boolean values. I want to simply change value of one field in db using checkbox. Code is like this:
Collection_controller:
def update
#collection = Collection.find(params[:id]).album
if #collection.update_attributes(:for_sale)
flash[:success] = "success"
redirect_to current_user
else
flash[:success] = "not working"
end
end
def collection_params
params.require(:collection).permit(:to_buy, :for_sale)
end
and form:
<%= form_for collection do |f| %>
<div><%= f.check_box :for_sale%></div>
<%= f.submit "sale", class: "btn btn-primary" %>
<% end %>
Is there anyone who know why it is not working?
EDIT
One important fact, after clicking 'submit' I have flash message 'success'. So why I dont see the changes? It is problem in controller, or somewhere else?
First of all this should be hash of parameters.
http://apidock.com/rails/ActiveRecord/Base/update_attributes
You need to pass in what you want to update. Possibly like so:
if #collection.update_attributes(collection_params)
But it looks like you're incorrectly setting your collection variable to be the album of the collection, so fix that too
#collection = Collection.find(params[:id]).album
should be
#collection = Collection.find(params[:id])

Rails object associated with button

<% #book.each do |book| %>
<%= book.title%>
<%=image_tag book.image_link%>
<%= book.authors%>
<%= book.description%>
<%= link_to 'Book IT' %>
<%= link_to 'Read IT' %>
<%= link_to 'Own IT' %>
<% end %>
So heres a copy of my code that prints the title, image, and author of a book searched. I am trying to associate the 'Book IT' link to add that particular object to my "Book it" library/table so that when i click on my 'Book It' Library link it will display that book.
A few other questions. Should I replace the link with a button? if so will the button be associated with the object through the loop?
you can do it with ajax request
<%= link_to 'Book IT',add_to_my_books_book_path,remote: true %>
routes
resoures :books do
member do
get :add_to_my_books
end
end
controller
def add_to_my_books
#book = Book.find params[:id]
#my_books = current_user.books
#my_books << #book
respond_to do
format.js {render alert("book added to your books")}
end
end
i assume that you has one_to_many relationship between users and books

Repopulating form on failed validation

I have a form for a user to create a question (in additon to user model, there's a question model, with nested answers) on their profile page. It submits from the users profile page /views/users/show.html.erb to the create action of the questions_controller.rb. If it doesn't validate, I think the default for Rails is to render the form(with the invalid information in the form for the user to edit). However, since I'm submitting the form for the question model from the users profile page the prepopulation isn't happening upon failed validation; the user is forced to enter all the information in the form again. Is there a way in this context to get the form on the users show page to fill out with the information that was entered prior to submission?
questions_controller
def create
#question = current_user.questions.build(params[:kestion])
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
###render :action => 'show'
redirect_to current_user
end
end
Update
I've changed the end of the create method too
Redirect ( : back ), :notice => "something went wrong.try again"
But I still can't get the form to populate, and the validation error messages aren't showing either, only the flash notice.
Update
The show method of the users controller creates the new Question (along with the user)
def show
#user = User.find(params[:id])
#question = Question.new
3.times {#question.answers.build}
end
The /views/users/show.html.erb
<%= form_for #question do |f| %>
<% if #question.errors.any? %>
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question
from being saved: </h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li> <%= msg %></li>
<% end %>
</ul>
<% end %>
<p>
<%= f.label :content, "Question"%>
<%= f.text_area :content, :class => 'span4', :rows => 1 %>
</p>
<p>
<%= f.label :link, "QuoraLink" %>
<%= f.text_field :link, :class => 'span4', :rows => 1 %>
</p>
<%= f.fields_for :answers do |builder| %>
<p>
<%= render 'answer_fields', :f => builder %>
</p>
<% end %>
<p><%= link_to_add_fields "Add Answer", f, :answers %></p>
<p><%= f.submit %></p>
<% end %>
the answer_fields partial rendered from the questions partial
<p class="fields">
<%= f.label :content, "Answer..." %>
<%= f.text_field :content, :class => 'span3', :rows => 1%>
<%= f.label :correctanswer, "Correct" %>
<%= f.check_box :correctanswer, :class => 'span1' %>
<%= link_to_remove_fields "remove answer", f %>
</p>
Currently, in views/users/show.rb you do
#question = Question.new
that creates an empty new question. Then you populate the forms with this empty model.
What you could do instead is:
if session[:question]
#question = #user.questions.new(session[:question])
session[:question] = nil
#question.valid? # run validations to to populate the errors[]
else
#question = Question.new
end
Now all what's left to do is populating session[:question] in your questions_controller before redirecting to :controller=>"users", :action=>"show". Something like:
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
session[:question] = params[:question]
redirect_to current_user
end
You may need to work on serialization/deserialization additionally for populating/using session[:question]. I didn't try to compile, so am not sure.
All this is needed because when you do redirect_to your processing of the user request ends, the user browser gets a redirect status code from your server and goes for another page, sending you a new request (which lands on the path, and eventually controller/action, to which you redirected to). So, as soon as you return from the request processing, all your variables are lost. For the next request you start from scratch.
The render :action => "show" approach (that was in the original scaffold and that you commented out) worked because you didn't return back to user but simply rendered the template with a specific name using the variables you already had in place (including #question, on which 'save' was called and failed, and thus internally validations were called and populated the errors object).
Actually, that reminded me that you may want to use another approach. Instead of passing parameters through session[] and redirecting to UsersController, you may want to populate all required variables and just render the view from that controller. Like below:
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
#user = current_user
render "users/show"
end
Firstly, the reason that using redirect_to instead of render doesn't repopulate the form is that when you redirect_to, the controller logic for the action is run, whereas using render ignored the controller logic.
So when you render :action => 'show' (the "default" behaviour), it renders show.html.erb, with #question set like this:
#question = current_user.questions.build(params[:kestion])
When you redirect_to current_user, it renders show.html.erb with #question set using the code in your show action:
#question = Question.new
3.times {#question.answers.build}
This is why you get a new (blank) form, instead of a pre-populated one.
Is it really that important that you use redirect_to? If it is, you'll need to get your show method to do the validation. For example, you could rewrite your show method to something like:
def show
#user = User.find(params[:id])
if params.has_key?(:kestion)
#question = #user.questions.build(params[:kestion])
else
#question = Question.new
3.times {#question.answers.build}
end
end
and then make your form point at that page, with something like:
<%= form_for(#question, url: users_path(#question.user) do |f| %>
...
<% end %>
(depending on how your routes are set up and named). Of course, by that point the whole thing become horribly un-RESTful, a bit of a mess, and definitely not the Rails way of doing things. (The other, worse option would be to redirect back and pass the params through a get query.) In my opinion, you lose a lot for a minor gain, and I'm not sure that I'd really recommend it.

checkboxtag in forms

Im looking for the following thing: an array of all users (only 6 in this case) with a checkbox in front of their name, resulting in a list of selectable players for the game.
Current code:
<%= form_for #game, url: games_path, :method => "post" do |f| %>
<%= f.label :name %>
<%= f.text_field :name, :value => "#{current_user.name}\'s Game" %>
<%= f.fields_for :participants do |ff| %>
<%= ff.label :user_id %>
<%= ff.text_field :user_id %>
<%= ff.check_box :user_id %>
<% end %>
<%= f.submit "Create Game", class: "btn btn-primary" %>
<% end %>
I'm now having 3.times { #game.participants.build } in my controller which effectively gives me 3 textfields in which i can fill in the participant id in order to make a record in the table participants (which is linked to games).
I've been looking around for 1.5h now and i cant seem to find a proper answer. What i need is a syntax that gives me a list of all current users (say #users) with a checkbox attached to it. When I click the checkbox it should add its id to the parameters and i should be able to create a new game with the linked participant id's. However I'm getting some problems with the ID's attached to the check_box which always seems to be 1. I've read some stuff about checkboxes being a pain with hashes, but I have no other solution atm.
I tried:
<% #users.each do |i| %>
<%= check_box_tag "alternate_numbers[#{i}]" %> <%= i.name %><br />
<% end %>
But i see no way to get that fixed up part of the form itself.
GamesController code (edit):
def new
#users = User.paginate(page: params[:page])
#games = current_user.games
#game = Game.new
3.times { #game.participants.build }
end
def create
#game = Game.new(params[:game])
#newround = #game.rounds.new
#newround.storyFragment = "New story!"
if #game.save && #newround.save
flash[:success] = "Created!"
redirect_to game_path(#game.id)
else
redirect_to root_url
end
end
It's very vague to describe since im not exactly sure how to accomplish this.
In short: the check_box should contain the value of the user_id in the loop. I'm now filling in a manual ID with the text_field helper but i'd like to have the checkbox linked to the username that is right next to it in the view.
Any guidelines/solutions/tips?
Thx
Okay, so you're making a form for a new Game. You now have to feed that new Game, along with some Participants to your view.
def new
#game = Game.new
#participants = User.all # or the users you want
end
Now use those in your view. You were on the right track. Depending on how your create action works:
<% #participants.each do |p| %>
<%= check_box_tag "participants[#{p.id}]" %> <%= p.name %>
<% end %>
I think what you were missing was the documentation for check_box_tag. The input attribute name is the argument.
You also seem to have a lot of logic in your controllers. Remember to keep the logic in the models, and only use the controllers to give the right objects to your views, and taking them for saving, for example. As the saying goes, "fat model, skinny controller".

Resources