How to get params with link_to in rails? - ruby-on-rails

My users have reviews, review may be negative and positive
And now i want show positive and negative reviews for other users
users_controllers.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#reviews = Review.where(for_user_id: #user, negative: false)
#reviews = #reviews.where(negative: params[:negative]) if params[:negative].present?
#reviews = #reviews
end
end
and my view
views/users/show.html.erb
<%= link_to 'Negative reviews', user_path(negative: true) %>
<%= link_to 'Positive reviews', user_path(negative: false) %>
<% #reviews.each do |review| %>
<li>
<div class="user_data">
<div class="user_review_left">
<%= link_to (avatar_for review.user, size: "50x50"), review.user %>
</div>
<div class="user_review_right">
<%= link_to review.user.name, review.user %>
<div class="user_post_name">
review for: <%= link_to (truncate review.post.name, length: 50), review.post %>
</div>
</div>
</div>
<div class="post_review">
<%= review.body %>
</div>
<div class="review_date">
<%= l review.created_at, :format => :my %>
</div>
</li>
<% end %>
</ul>
</div>
how i can add links for this code?
if user link the controller return #reviews with params
Thanks

<%= link_to 'Negative reviews', user_path(#user, negative: true) %>
and
<%= link_to 'Positive reviews', user_path(#user, negative: false) %>
and change your show method:
def show
#user = User.find(params[:id])
#reviews = Review.where(for_user_id: #user, negative: (params[:negative] || false))
end
even if I ask myself why you can't do that:
def show
#user = User.find(params[:id])
#reviews = #user.reviews.where(for_user_id: #user, negative: (params[:negative] || false))
end

You could pass the user ID and the review parameter
link_to "Reviews", user_path(id: #user.id, negative: true)

As said by coorase appending a parameter to the end of the args will work.
<%= link_to 'Negative reviews', user_path(#user, negative: true) %>
will create a url like: root/users/:id?negative=true
if you debug inside of the controller action which handles this and evaluate the value of 'params' you will see something like:
{"negative"=>"true", "controller"=>"root", "action"=>"index"}
this is your params hash and it means that
params[:negative] ==> true
(I recommend getting the 'pry' gem and inserting 'binding.pry' inside the controller action if you don't have a good debugger you use)
Please be more specific in explaining why this output doesnt work for your situation and I may be able to help you formulate better parameters

Related

How do i get the id of a model that i just created through form_with basically from one controller to another in Rails

Sort of new in rails so i might be doing things the wrong way
show.html.erb:
<% #feature.each do |p| %>
<br>
<h1><%= p.name %></h1>
<%= p.unit_price %>
<%= render partial: "shared/featureuse_form", locals: {feat_use: #feat_use , feature: p} %>
<%= button_to'Change' , feature_use_path(1) , :class => 'btn btn-primary' ,method: :delete %>
<% end %>
Right here in feature_use_path how do i get an id to pass it in order to make a delete button as i havent even created the model yet or its saved in its own controller should
_featureuse_form.html.erb:
<%= form_with model: feat_use do |f| %>
<%= f.number_field :total_units ,value: feature.max_unit_limit %>
<%= f.hidden_field :feature_id, value: feature.id %>
<%= f.hidden_field :usage_id, value: current_user.usage.id %>
<%= f.submit "confirm", id: "button"%>
<% end %>
Plans Controller
class PlansController < ApplicationController
before_action :authenticate_user!
def index
#plan = Plan.all
end
def show
#plan = Plan.find(params[:id])
#feature = #plan.features
#feat_use = FeatureUse.new
end
end
class FeatureUsesController < ApplicationController
def create
feature_use = FeatureUse.new(feature_use_params)
feature_use.total_units = params[:feature_use][:total_units]
feature_use.feature_id = params[:feature_use][:feature_id]
user = current_user.usage
feature_use.usage_id = user.id
feature_use.save
end
end
You're right that you can't create a button (method: :delete or otherwise) that relies on a record that doesn't yet exist.
Usually, a button like this would only be relevant to existing records anyway.
So, it's common to see an if statement like this:
<% if #feature_use.persisted? %>
<%= button_to 'Change' , feature_use_path(#feature_use.id) , :class => 'btn btn-primary', method: :delete %>
<% end %>
.persisted? returns false if the record is new and un-saved.

My Rails button is not updating the database

I created a button where users can input stuff in a field and then press the button to update the database (put request) which can be seen here in show.html.erb:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
<br>
<%= #user.email %>
<% if #errors %>
<p>THE FORM COULD NOT BE SAVED </p>
<ul id='errors'>
<% #errors.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<% end %>
<br>
<% if is_admin? %>
<% if !#user.admin %>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user) do |f| %>
<%= f.label :wistia_project_id %>
<%= f.text_field :wistia_project_id, class: 'form-control' %>
<%= f.submit "Save", :action => "set_wistia_project_ID", :method => :patch, :form_class => "form-control" %>
<% end %>
</div>
</div>
<% end %>
<% end %>
</h1>
</section>
</aside>
</div>
The function is in user_controller.rb:
# Sets wistia_project_ID.
def set_wistia_project_ID
#user = User.find(params[:id])
#user.set_project_id
unless #user.valid?
#errors = #user.errors.full_messages
render :show
end
end
That function calls another function, just to separate things more clearly. This other function lives in user.rb:
# Sets the wistia_project_ID.
def set_project_id!(val)
self.wistia_project_ID = val # self is necessary here
save # or self.save, but the self is unnecessary here
end
My routes.rb:
.
.
.
resources :users do
member do
patch 'set_wistia_project_ID'
end
end
My problem is that right now, when you press the button, it says: Completed 500 Internal Server Error in 26ms (ActiveRecord: 0.7ms)
and
NoMethodError (undefined method `set_project_id' for #<User:0x000055b1a0914ab8>
2019-06-26T14:46:34.940086+00:00 app[web.1]: Did you mean? wistia_project_id):
Zavitoski got it right. I suggest, however, that you're doing a number of things more fundamentally wrong. Given that you're early in your rails journey, I hope you don't mind if I point a few things out.
First, and to be nit-picky, yes, you created a button. But, it is not a button "where users can input stuff in a field and then press the button to update the database". You created a button on a form. And you created a field on that form. The user can input stuff into the field. And when clicked, the button submits the form which includes the information in the field.
Now, on that form, you did:
<%= form_for(#user) do |f| %>
<%= f.label :wistia_project_id %>
<%= f.text_field :wistia_project_id, class: 'form-control' %>
<%= f.submit "Save", :action => "set_wistia_project_ID", :method => :patch, :form_class => "form-control" %>
<% end %>
There are a few things wrong with:
:action => "set_wistia_project_ID"
First, set_wisteria_project_ID is not a very ruby-ish action name. set_wistia_project_id would be more like it. Also, you're using old-form key-value formatting. And, you can use a symbol instead of a string for your action name so your code is prettier. Something, perhaps, like:
<%= f.submit "Save", action: :set_wistia_project_id, method: :patch, form_class: "form-control" %>
But, that's a mistake, too. Because you don't need a set_wistia_project_id action. (It's an action or a method, not a function.) You already have the update action. And form_for is smart enough to submit to this action if #user is an instance of User. So, really, you should do:
<%= form_for #user do |f| %>
<%= f.label :wistia_project_id %>
<%= f.text_field :wistia_project_id, class: 'form-control' %>
<%= f.submit "Save", form_class: "form-control" %>
<% end %>
I'm not sure what form_class is, but I'll trust that it's correct.
Now, in your UsersController, just do:
class UsersController < ApplicationController
def update
#user = User.find(params[:id])
if user.update(user_params)
# do something successful
else
# do something unsuccessful
end
end
private
def user_params
# NOTE: You'll probably want to permit other stuff here, too.
params.require(:user).permit(:wistia_project_id)
end
end
Get rid of this:
class User < ApplicationRecord
# Sets the wistia_project_ID.
def set_project_id!(val)
self.wistia_project_ID = val # self is necessary here
save # or self.save, but the self is unnecessary here
end
end
Because you're just duplicating the update method. And, you probably want that attribute to be wistia_project_id, not wistia_project_ID. (Again, you never see _ID as the suffix in rails core and you might as well be conventional.) And, if you make sure you have your association set up correctly, ActiveRecord should make sure that wistia_project_id is actually a valid value.
And write your routes.rb like this:
resources :users
Because you don't need all that set_wistia_project_id business.
It appears that you are not calling the function by the name you defined, neither passing the parameter (project_id) needed.
def set_wistia_project_ID
#user = User.find(params[:id])
#user.set_project_id!(params[:wistia_project_id])
unless #user.valid?
#errors = #user.errors.full_messages
render :show
end
end
This should use the function you created and pass the parameter from the form.

Rails:ArgumentError in MethodTypes#edit

I tried to make an edit for ruby on rails, but it shows me the argument error about the edit. I am confused about this question.
Then, I have tried to put the different argument into index.html.erb However, it still does not work. For example m.id and m
This is index.html.erb
<% #methodtypes.each do|m| %>
<tr>
<td><%=m.name %></td>
<td><%=m.desp %></td>
</tr>
<%= link_to "Edit", edit_method_types_path(m.id) %>
<% end %>
<%= link_to "Create Method", new_method_types_path %>
This is my controller file:
class MethodTypesController < ApplicationController
def index
#methodtypes = MethodType.all
end
def show
#methodtype = MethodType.find_by_id(params[:id])
end
def create
#methodtype = MethodType.new(method_params)
#methodtype.save
if #methodtype.save
redirect_to method_types_path
else
render :new
end
end
def edit
#methodtype = MethodType.find_by_id(params[:id])
end
def new
#methodtype = MethodType.new
end
private
def method_params
params.require(:method_type).permit(:name, :desp)
end
This is my edit page which is edit.html.erb:
<%= form_for #methodtype do |f| %>
<div>
<%= f.label :name %>
<%= f.text_area :name %>
</div>
<div>
<%= f.label :desp %>
<%= f.text_field :desp %>
</div>
<%= f.submit %>
<% end %>
The result should show that I can edit my text. but, it shows the ArgumentError in MethodTypes#edit. Does someone can give me some suggestion, I do not know how to fix that.....
Wrong edit url path
It should be <%= link_to "Edit", edit_method_type_path(m.id) %> instead of <%= link_to "Edit", edit_method_types_path(m.id) %>
Also check your routes file It seems you are defining
resource: method_types
Change to
resources: method_types
<%= link_to "Edit", edit_method_types_path(m.id) %> should be <%= link_to "Edit", edit_method_type_path(m) %>, note that type is in singular.
Run rails routes -g method_type to confirm it.
Also, change the MethodType.find_by_id(params[:id]) to MethodType.find(params[:id]) in the controller.
Btw, you are calling save twice in your create method:
def create
#methodtype = MethodType.new(method_params)
#methodtype.save # delete this line
if #methodtype.save
redirect_to method_types_path
else
render :new
end
end

how to retreive from memory an object associated to a destroyed object

My application has a Micropost model and a Comment model.
I introduced in the Micropost partial links for showing/hiding and refreshing comments:
<li id="micropost-<%= micropost.id %>">
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content">
<%= micropost.content %>
<%= image_tag micropost.picture.url if micropost.picture? %>
</span>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
~ <%= link_to "Refresh comments", fetch_comments_path(micropost), remote: true %>
<% end %>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
...
<% end %>
</div>
<% end %>
<div class="comments-section">
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
</div>
</li>
This links are added to the page after creating the first comment and are loaded if the micropost has comments.
However, in case there is just one comment and it is deleted, they are useless so I would like to remove them with Ajax via the destroy action of the comments controller.
I am having my troubles to realize this.
The main problem is that I cannot refer to the micropost using the to-be-destroyed comment.
Once the comment is destroyed any #micropost = #comment.micropost association would return a nil object:
def destroy
#comment = current_user.comments.find_by(id: params[:id])
#micropost = #comment.micropost
#comment.destroy
respond_to do |format|
format.html do
flash[:success] = "Comment deleted"
redirect_to request.referrer || root_url
end
format.js
end
end
Thus, inside create.js.erb I cannot use a if #micropost.comments.nil? remove links conditional
Moving #comment.destroy after the respond_to block would not work for format.html, without refreshing the page.
If it worked, I could use a if #micropost.comments.count == 1 remove links conditional in create.js.erb
I cannot move #comment.destroy inside the format.html block, because it would not be used by format.js.
What solution can I use?
The delete link in the comment partial is:
<%= link_to "delete", comment, method: :delete, remote: true %>
Is it possible to pass in link_to a params value equal to micropost.id, such as:
<%= link_to "delete", comment, method: :delete, micropost_id: micropost.id, remote: true %>
so that I can write in the destroy action:
#micropost = Micropost.find(params[:micropost_id]) ?
When you destroy your object it is destroyed form database and all reference keys are destroyed immediately. So you can first grab post Id and the remove comment.
def destroy
#micropost_id = #comment.micropost.id
#comment.destroy
end
Now you can use #micropost_id to take another action or to redirect to the parent post like this:
redirect_to '/microposts/'+ #micropost_id
Or
redirect_to MicroPost.find(micropost_id)

Rails 4 - Combine Params from Previous Page (Pass Array in Hidden Field?)

On Rails 4. I'm working on an e-commerce app where a user can choose to go through a wizard-like process.
First the user selects a color scheme,
then selects products from two different pages,
then the results of those product selections are displayed on a fourth page.
No rows are created or updated in the database, I just want the results to be displayed on the fourth page (because this info is then fed to a third-party service).
Because the array would be no more than five or six choices, I am passing the product ids through the URL params. Here's the controller (let's say on the second page the user selects paper products and on the third page the user selects pencil products)
class WizardController < ApplicationController
def index
# Where the user clicks on a color scheme link
end
def paper
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
end
def paper_submit
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids]) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids] + [:paper_ids]) } # ?? Not sure what goes here
end
end
def finish
# Haven't gotten here yet
end
private
def color_scheme_params
params.require(:wizard).permit(:color_scheme_id, :id)
# Also not too sure about this area either
end
end
Routes:
get '/wizard/paper', controller: 'wizard', action: 'paper'
put '/wizard/paper', controller: 'wizard', action: 'paper_submit'
get '/wizard/pencils', controller: 'wizard', action: 'pencils'
put 'wizard/pencils', controller: 'wizard', action: 'pencils_submit'
get '/wizard/finish', controller: 'wizard', action: 'finish'
resources :wizard
Form for the second page (selecting paper products)
<%= form_for([#color], html: {multipart: true}, url: {action: "paper_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Paper").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Select Pencils", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
So far this all works fine. But, the problem is when the user makes product selections on the third page and reaches the fourth page. Ideally I want my application to combine the product id params from the second page with the different product ids from the third page.
<%= form_for([#color], html: {multipart: true}, url: {action: "embellishments_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<!-- A hidden field maybe?? This does not work though -->
<%= f.hidden_field(:paper_ids, multiple: true, value: #paper) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Pencil").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Purchase Your Selections", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
It seems like a simple thing, I just want to combine an array from two different pages from the URL params but I can't figure out how to do this. Don't really want to use a gem for this because this is all I need to figure out. Thanks for any help.
Just put your variables into session:
def paper_submit
session[:paper_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
session[:pencil_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def finish
#all_products = Product.where(
enabled: true,
color_scheme_id: params[:color_scheme_id],
id: session[:paper_ids] + session[:pencil_ids]
)
end
finish.html.erb:
<% #all_products.each do |product| %>
<%= product.name %>
<br />
<% end %>
You should add those two arrays and make something like:
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
product_ids: params[:ids] + [:paper_ids]) }
end
end
Then in your form:
<% #product_ids.each do |id| %>
<%= f.hidden_field_tag 'product_ids[]', id %>
<% end %>
Then in your last finish action do whatever you want.

Resources