I have a query that is checking if a certain values exist in the DB and returns an array if they exist
#canEditTask = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
The problem is that this can return nil
#taskEdit = #canEditTask
but my each method in my html still fails due to nil undefined methodeach' for nil:NilClass`
.
<% #taskEdit.each do |task| %>
<%= task.id %>
In that case what is the best way to prevent a nil from breaking my code?
Edit
Controller code
def index
#canEditTasks = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
end
def show
#taskEdit = #canEditTasks
rescue ActiveRecord::RecordNotFound
render :file => 'public/404.html'
end
View code
<div>
<% #taskEdit.each do |task| %>
<%= task.id %>
<% end %>
</div>
You are setting #canEditTasks in your index method and trying to use it in your show method... if you are confused by this you should probably go back to the basics and read/watch some Rails tutorials (sorry if I'm missing something here...).
When you assign #taskEdit = #canEditTasks in the show action, #canEditTasks is nil, which means #taskEdit is also nil.
Actions are run one at a time, it seems your code is expecting index to run first, and then show would run after that. That isn't how Rails works by default. If you want to run some code that is shared between several actions, I would suggest a before_filter.
before_filter :set_can_edit_tasks
def index; end
def show
#taskEdit = #canEditTasks
rescue ActiveRecord::RecordNotFound
render :file => 'public/404.html'
end
private
def set_can_edit_tasks
#canEditTasks = Accessor.where("accessor_id = ? AND access_right = ?", current_user, true)
end
I would prefer to use a .to_a after the active record where. so no error when a nil array is looped ;) avoids condition in views.
Related
I have something like that in my controller:
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
I want to use search method in index action but I don't want to remove my #votes variable from index. If I use before_action, it calls method before the action so #votes doesn't change. Is it possible to call search method after my votes variable or ignore the variable without removing.
I normally go with this method when I'm looking to build a simple search:
http://railscasts.com/episodes/37-simple-search-form
Create a method in your vote.rb file:
class Vote
def self.search(search)
if search
self.where(:all, conditions: ['name LIKE ?', "%#{search}%"])
else
self.where(:all)
end
end
end
This means when you do Vote.search('term'), you'll bring up any records with a similair name. Replace name for whatever term you're searching for (i.e. title or category).
If there is no search term entered this method simply returns every instance. This means you can leave your controller looking like this:
def index
#votes = Vote.search(params[:search])
end
Finally the view for this would be something like:
<% form_tag votes_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
This will send a get request to the votes_path (the index action on your controller), with the search term parameter. If one is entered the search will return the relevant instances, and if not it will return all.
Try
class TempController < ApplicationController
after_action :search
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
end
I am just trying to get two parameters from a view to my controller. I'm using Rails 4.2.x and strong params are killing me.
One param, :query, resolves correctly. However the second param, :location, throws the error in the questions title. I have Googled the issue but everyone's scenario seems to be different and their solutions (relatively) unique.
The view in question is index.html.erb which only contains a simple search form.
<%= form_tag("/searches", action: "create", method: "post") do %>
<div>Job Title</div>
<%= text_field_tag(:query) %>
<div>Location</div>
<%= text_field_tag(:location) %>
<%= submit_tag("Go") %>
<% end %>
The controller in question is searches_controller.rb.
class SearchesController < ApplicationController
def index
binding.pry
end
def show
binding.pry
end
def update
end
def create
#query = search_params["query"].to_s || nil
#location = search_params[:location].to_s || nil
binding.pry
end
def delete
end
private
def search_params
params.require(:query).permit(:location)
end
end
The stack trace points to the search_params method, and shows me that I have the following params in the controller
{
"utf8"=>"✓",
"authenticity_token"=>"DEcTwT/NnSY3S3n25zZGXD+KRZcsRkWj9bmN57AMNivFbMXwHF5Vf/psgzSMkZPBa+OWJgafXYGdW+o5KN3xxg==",
"query"=>"titleofcoolstuff",
"location"=>"milwauke",
"commit"=>"Go"
}
What am I missing?
Strong parameters is for providing a hash of attributes, for example:
<%= form_for #user do |f| %>
## form
<% end %>
This may send parameters like this:
"user" => { "name"=> "Your Name", "age" => "23", "location" => "USA" }
Strong parameters in this case would be instructing rails to process the users hash of attributes and specifically these attributes, like this:
params.require(:user).permit(:name, :age, :location)
In your case, you are passing in individual parameters (not hashes of attributes), so if you want to grab them, you grab them explicitly:
def create
#query = params[:query].to_s || nil
#location = params[:location].to_s || nil
#do something
end
No need for strong parameters to whitelist model attributes here. Hope this helps.
In your case
"query"=>"titleofcoolstuff",
"location"=>"milwauke",
"commit"=>"Go"
since your data are not wrapped with any keys (they are at the root) so you can simply access them using like params[:query].
Whitelisting/Strong params
We need to whitelist params only for mass assignment. like #user.update(user_params) Here, unless the params sent by users in user_params are whitelisted i.e. permitted using .permit method; the update method will throw an exception ActiveModel::ForbiddenAttributes.
In your case since your not updating anything you do not need to create strong params for it.
def create
#query = params["query"].to_s || nil
#location = params[:location].to_s || nil
binding.pry
end
If you are gonna do mass assignment in future you have to whitelist your params
For more info see https://cbabhusal.wordpress.com/2015/10/02/rails-strong-params-whilisting-params-implementation-details/
I have a piece of code in Rails,
def create
#registration = Registration.new(registration_params)
if #registration.save
redirect_to #registration.paypal_url(registration_path(#registration))
else
render :new
end
end
I took it from tutorial. But I need just in this line:
#registration.paypal_url(registration_path(#registration))
Now, about my own controller, feed_controller, where
def create
#feed = Feed.new(check_params)
end
In the view erb file I put:
#feed.paypal_url(feed_path(#feed))
In my feed.rb (model):
def paypal_url(return_path)
values = {
business: "merchant#gotealeaf.com",
cmd: "_xclick",
upload: 1,
return: "#{Rails.application.secrets.app_host}#{return_path}",
invoice: id,
amount: course.price,
item_name: course.name,
item_number: course.id,
quantity: '1'
}
"#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" + values.to_query
end
Rake routes:
feed GET /:locale/feed(.:format) feed#index
feed#create POST /:locale/feed/create(.:format)
feed#new feed_new GET /:locale/feed/new(.:format)
feed#destroy feed_destroy GET /:locale/feed/destroy(.:format)
feed#edit feed_edit GET /:locale/feed/edit(.:format)
feed#update feed_update GET /:locale/feed/update(.:format)
But it prints the next error:
undefined method `paypal_url' for <#Feed::ActiveRecord_Relation:0x007fee24f5fc98>
How can I fix it? What is the problem?
UPDATE
def index
#current_user_is = current_user.email
session[:email] = #current_user_is
session[:id] = current_user.id
unless (current_user.member.present?)
#member = Member.new(:user_id => current_user.id)
#member.save()
redirect_to '/feed'
else
#new_feed = Feed.new
#feed = Feed.where(:member_id => current_user.member.id)
#category = Category.all
render 'home/uploads'
end
end
Simply use def self.paypal_url(return_path) instead of def paypal_url(return_path).
Explanation
You ran into your problem by defining a Class Method instead of an Instance Method, there's other posts discussing this.
The basic difference is, when defining:
def self.get_some_url
# code to return url of an instance
end
you can easily get the desired url of any objects, as in a view:
<% #feeds.each do |feed| %>
<%= feeds.get_some_url %>
<% end %>
Now calling Feed.get_some_url on the class would make no sense. Which url of the thousands would it call?
But there is a lot of use for class methods (where you define the method without self as you did)
def get_top_5
# code to return the top 5 most viewed feeds
end
Since this has nothing to do with a single instance, you define it for the entire Class. Leading to this call: Feed.get_top_5, which makes perfectly sense.
The second problem was not understanding the difference between where & find, this post will help you out with that.
I searched and searched, but nothing solved my problem. Here's my controller:
def show
#topic = Topic.find(params[:id])
#topic.posts = #topic.posts.page(params[:page]).per(2) # 2 for debugging
end
That functions just fine, because the topic view is reduced to two posts. However, when I add this to show.html.erb:
<%= paginate #topic.posts %>
I'm given this error:
undefined method `current_page' for #<ActiveRecord::Relation:0x69041c9b2d58>
Try with:
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts.page(params[:page]).per(2)
end
And then:
<%= paginate #posts %>
If you get pagination errors in Kaminari like
undefined method `total_pages'
or
undefined method `current_page'
it is likely because the AR scope you've passed into paginate has not had the page method called on it.
Make sure you always call page on the scopes you will be passing in to paginate!
This also holds true if you have an Array that you have decorated using Kaminari.paginate_array
Bad:
<% scope = Article.all # You forgot to call page :( %>
<%= paginate(scope) # Undefined methods... %>
Good:
<% scope = Article.all.page(params[:page]) %>
<%= paginate(scope) %>
Or with a non-AR array of your own...
Bad:
<% data = Kaminari.paginate_array(my_array) # You forgot to call page :( %>
<%= paginate(data) # Undefined methods... %>
Again, this is good:
<% data = Kaminari.paginate_array(my_array).page(params[:page]) %>
<%= paginate(data) %>
Some time ago, I had a little problem with kaminari that I solved by using different variable names for each action.
Let's say in the index action you call something like:
def index
#topic = Topic.all.page(params[:page])
end
The index view works fine with <%= paginate #topic %> however if you want to use the same variable name in any other action, it throu an error like that.
def list
# don't use #topic again. choose any other variable name here
#topic_list = Topic.where(...).page(params[:page])
end
This worked for me.
Please, give a shot.
First, I've generated scaffold called 'item'
I'd like to check which fields of the item are modified. and I've tried two possible attempts, those're not work tho.
First Attempt!
def edit
#item = Item.find(params[:id])
#item_before_update = #item.dup
end
def update
#item = Item.find(params[:id])
# compare #item_before_update and #item here, but #item_before_update is NIL !!!
end
Second Attempt!
I looked for the way passing data from view to controller and I couldn't.
edit.html.erb
<% #item_before_update = #item.dup %> # I thought #item_before_update can be read in update method of item controller. But NO.
<% params[:item_before_update] = #item.dup %> # And I also thought params[:item_before_update] can be read in update mothod of item controller. But AGAIN NO
<% form_for(#item) do |f| %>
# omitted
<% end %>
Please let me know how to solve this problem :(
Attributes that have changes that have not been persisted will respond true to changed?
#item.title_changed? #=> true
You can get an array of changed attributes by using changed
#item.changed #=> ['title']
For your #update action, you need to use attributes= to change the object, then you can use changed and changed? before persisting:
def update
#item = Item.find(params[:id])
#item.attributes = params[:item]
#item.changed #=> ['title']
... do stuff
#item.save
end