In my Rails app I have a users_controller with an action that displays a users profile, but I would like it to only display a users profile if the user has a specific value set in the database called is_rec set to true.
The below is my attempt but it doesn't work. I used a scope for the index and that worked well but I wasn't able to get a scope to work when I was working with the show action
def rec_profile
#user = User.find(params[:id])
#user if #user.is_rec == 'true'
end
I could do something like this in the view but I wanted to see if there was a way to do it in the controller instead?
<% if #user.rec == 'true' %>
<% show page here %>
<% end %>
You can use find_by and pass 1 or more attributes to look for in your database. So you could pass the id and is_rec attributes and get your user.
User.find_by(id: params[:id], is_rec: true)
Or you can use where to get all users where is_rec is true and then filter for the user whose id matches with params[:id]:
User.where(is_rec: true).find(params[:id])
Which eventually can be converted to a scope for easy access:
scope :with_rec, -> { where(is_rec: true) }
For being used then as:
User.with_rec.find(params[:id])
with_rec is just an example name as scope, you could use whatever you want.
Related
I would like to have the ability to create an order directly from the listings show page instead of having to be directed to a new orders page.
I have a Listing (listingcontroller show method) which can be purchased by clicking a button to go to an orders page (orderscontroller create method).
In what way can I have the order form directly on the listings show page?
I have tried adding the form, but I get error:
First argument in form cannot contain nil or be empty
<%= form_for([#listing, #order]) do |form| %>
When I take the Orders controller create method and put it in the Listings Controller Show method i get this error:
Couldn't find Listing without an ID
Here's the form_for I want within the Listings Show Page:
<%= form_for([#listing, #order]) do |form| %>
....
Orders Controller create:
#order = Order.new(order_params)
#listing = Listing.find(params[:listing_id])
#seller = #listing.user
#order.listing_id = #listing.id
#order.buyer_id = current_user.id
#order.seller_id = #seller.id
...
Routes:
resources :listings do
resources :orders
end
listing model:
has_many :orders
category model:
has_and_belongs_to_many :listings
I tried taking the orders create method and injecting it into the Listings show method with "def create" and without. I put "#listing = Listing.find(params[:listing_id])" ahead of the create method (when using "def create" and i would still get the error it needs an id. Even when I get that error, at the bottom of the webpage the request shows the listing ID is there.
I tried using a hidden field in the form but didn't work for me.
Do I need to do something to the controllers or is there a way to load the :listing_id into the form somehow. This is probably something very quick and simple for some of you but why won't it load on the listings show page, but loads fine in the orders create page?
Easy approach.
Your show action in listing_controller.rb should have the following code:
def show
#listing = Listing.find(params[:listing_id])
#order = #listing.orders.build
.
.
.
end
Your views/listings/show.erb should have the following code
<%= form_for(#order, url: listing_orders_path(#listing)) do |f| %>
.
.
.
<%= end %>
This way you create an order to the listing (in memory) before you submit the form. You can add the listing id as a hidden field.
After submit the order you modify your orders_controller.rb this way:
def create
#listing = Listing.find(params[:listing_id])
#order = #listing.orders.build(params[...]) #select the params you need for the order creation. Since you create the order directly to the listing you don't need to add the listing_id to the order.
if #order.save
#do something
else
#do something
end
end
Keep in mind that using params[] directly you have security problems, please check about mass assignment: https://guides.rubyonrails.org/v3.2.8/security.html
You can achieve that by using AJAX call, where you will pass the url of orders action and other params. There will be no reload of page and you'll get the functionality right on the listings page.
Here is the link to have a look - How AJAX calls work.
I want to get the real id of a User due to a problem in the url for will_paginate in that I need to set it manually, so I want to get the target link for will paginate by a custom renderer method in the view like this,
<%= will_paginate #friends, :renderer => WillPaginateHelper::MyLinkRenderer %>
And the helper is something like,
module WillPaginateHelper
class MyLinkRenderer < WillPaginate::ActionView::LinkRenderer
include SessionsHelper
protected
def link(text, target, attributes = {})
if target.is_a?(Integer)
attributes[:rel] = rel_value(target)
target = "/users" + current_user.id + "/friends?page=#{target}"
end
attributes[:href] = target
tag(:a, text, attributes)
end
end
end
The line target = "/users" + current_user.id + "/friends?page=#{target}" is the important one where I need to set the url for will_paginate anchor links with the current user id.
Problem is that when the helper I am using is ran in the view to set the url, I get a error undefined local variable or method session..., you cannot use sessions hash in helpers so how to get the real id of the current_user to insert into variable. Do I delete/destroy the session get the id and create a new one? The problem is once I delete the session how to get the id once I delete the session and the user reference is deleted.
Reason
I have a friends#index action that is rendered in a div and upon initial call to url the pagination attaches correctly being the url users/:id/friends so each pagination request goes to the correct user and action. But this index view has "Unfriend" form attached to each displayed friend so you can destroy the friendship which goes to the destroy action of the friends controller so markup is eg <form... action="friends/177"...> and on full view reload of the index action from destroy action will paginate attaches to the last known link unless overriden. So when index action is fully rendered again pagination links are friends/177 which give a server error anyway and makes no sense as that record just got destroyed.
I have the current_user variables and id in my destroy action but I can not find a way to get them to my helper method, or simply get the current user id from the session.
Ok, so thanks to max and everyone for helping me. found this post and this answer here which you can do something like,
In your routes
get 'users/:cu_id/friends', to: 'users#index', as: :my_friends
And for the view
<%= will_paginate #friends, params: { controller: :users, :cu_id => current_user.id } %>
This will produce users/:cu_id/friends?page=2... of course :cu_id will be the actual id number, for pagination.
EDIT: Order is important here to if you have any other routes going to the same url eg, users/:user_id/friends when you nest resources, you need to put get 'users/:cu_id/friends',... below this, as rails will build the correct route for you for will paginate but come back in through the friends#index action when paginated and match eg users/1/friends through users/:user_id/friends as it is first in order in routes.rb. here in rails guide it explains how it works.
I'm trying to create a simple Rails app that will retrieve API data. My original intention were not to save the search to the database, which is why I used form_tag. My search works when I run in the console, but when I call #results or #first_match, it give me nil. Many thanks in advance.
Actor Controller Method
def index
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
Actor Form
= form_tag 'actors/show', method: :get do
= text_field_tag "Actor"
= submit_tag "Show me"
Routes
RailsApp::Application.routes.draw do
resources :actors
end
Update
Since I am routing in the show method in the form. I was able to retrieve the variables in my show method in the controller. I don't know if this is the best way though.
def show
#results = API::Topic.search([:actor])
#first_match = #results.values.first
end
I think, you need to use API::Topic.search(params[:actor])
I have a User model wich has a controller index and an '.all' scope
ex: User.all
Is there a decent way to switch to a different scope when you clic on a view link?
I want to display all user when a user clic an 'all' link or a scoped version when he clic on an other link.
Do i have to use a gem like has_scope?
Thanks
You can use scoped method, for example:
#users = User.scoped
#users = #users.your_scope if params[:your_scope_param]
all you have to do is to bind appropriate param to your "scoping" link, it should be like:
<%= link_to 'Scoped users', users_path(your_scope_param: true) %>
I have a small question regarding rails. I have a search controller which searches for a name in database, if found shows the details about it or else I am redirecting to the new name page. Is there anyway after redirection that the name searched for to automatically appear in the new form page?
Thanks in advance.
You can use the ActionController::Flash to pass data between actions.
def search(searchedName)
# perform search on DB
flash[:searchedName] = searchedName
redirect_to new_name
end
def new_name
end
new_name.html.erb:
<% if flash[:searchedName] %>
<%= text_field_tag flash[:searchedName] %>
<% end %>
Well, let's say you are saving this 'name' entered by user on a variable named #name.
So, on the controller that do the action of search, you did something like:
if #name
...#action if the name was found
else
session[:name] = #name
...#here is the action you did to redirect
On the declaration of the method called (you said it was 'new') :
def new
#name = session[:name] if session[:name] #I don't know exactly if the condition is this one,
#but you have to confirm that the session was instatiated
session.delete(:name) #to don't let garbage
...#continuous the action of show the new page
#and on the page you have access to a variable #name, that have the name searched before.