I have a relation between my model User and Request that is decoupled. I.E. There is no user_id field in the requests table.I have a finder to figure out what Requests a User can see that is different than the default ActiveAdmin call of
requests where user_id = x
I had assumed that if I had a method in my User class called requests that called this finder, ActiveAdmin would be able to figure it out but it doesn't. So here's some code. I previously assumed this would work to get the requests for the user:
class User
...
def requests
RequestFinder.new(self).find
end
...
end
Then I got this error:
PG::UndefinedColumn: ERROR: column requests.user_id does not exist
LINE 1: ...T 1 AS count_column FROM "requests" WHERE "requests"...
So I figured I should override the index method in the requests controller:
def index
#requests = RequestFinder.new(current_user).find.page(params[:page]).per(20)
end
But then I get the following error:
First argument in form cannot contain nil or be empty
vendor/bundle/ruby/2.2.0/gems/actionview-4.2.4/lib/action_view/helpers/form_helper.rb:432:in `form_for'
I'm not really sure how to reformat my requests controller to render the requests from the finder instead of from the user.
So as per usual I figure it out right after I post #facepalm.
If you want to pass any generic ActiveRecord::Relation to active admin index, just override the scoped_collection method making sure to add pagination, like so:
controller do
def scoped_collection
RequestFinder.new(current_user).find.page(params[:page]).per(20)
end
end
Related
Building a simple phone book app and have a concern regarding the following:
Each of my listed contacts has a number resource, and their relationship is defined in the routes file as follows:
config/routes.rb
resources :contacts do
resources :numbers
end
In my webapp thus far, I have it so that a user can create a contact and then create a number corresponding with that contact. I list the numbers for the contact, and when the user clicks on it (in order to route to the numbers#show page for that specific number, I get the following error:
NoMethodError in NumbersController#show
undefined method `numbers' for nil:NilClass
I've had this error a ton of times, and always it happened because the contact wasn't instantiated properly. But in my code, everything is being saved to db properly as per my rails console exploration. Below is the code throwing the error, found inside my numbers controller:
def set_number #to do item
#number = #contact.numbers.find(params[:id])
end
And the parameters being passed in, according to the error page, are the following:
Parameters:
{"contact_id"=>"1",
"id"=>"1"}
I set #contact via this method in the numbers controller:
def set_contact
#contact = Contact.find(params[:contact_id])
end
and I call it at the top as so:
before_action :set_contact
Given that there are parameters, and Rails console tells me both the contact and the number were saved properly, any idea what's wrong?
As I posted as a comment:
You have to have your before_action :set_contact before your before_action :set_number, otherwise you won't have the #contact when calling the :set_number.
All the before_action runs in the order that you added them :)
Cheers
Clearly the error seems to be in set_number method inside your controller. And the reason is #contact is nil.
So, as in above comments, your set_contact method may be running after set_number
Task: Showing the profile of an employee straight away after his login.
Issue:
class WelcomeController < ApplicationController
def index
#employee = Employee.find_by_email(params[#current_user.email])
end
end
I tried to code in many ways to associate the email of the current user with his respective details from the employees table and the farthest that I could get was it:
I am sure that I am writing something wrong in this line inside the index thing, but I am researching and all things that I found and tried did not get the employee related to the current user.
Try with this code:
class WelcomeController < ApplicationController
def index
#employee = Employee.where(email: current_user.email).first
end
end
When using Devise, the current user is an instance variable, so you don't need to prefix it with #.
If you are going to have a lot of users, is a good practice to create an index in your database for the email column.
I like kjmagic13's answer. Use the
#current_user.id
It pulls all the info associated with the user from the database
Mori's answer is also good.
The following SQL line in your logs corresponds to the Employee.find_by_email call:
SELECT "employees".* FROM "employees" WHERE "employees"."email" IS NULL LIMIT 1
As Mori pointed out, this means you're finding the employee with a nil email, which means that params[#current_user.email] is nil. Since you have no parameters, there's no need to refer to the params hash regardless. You should refer just to the #current_user.email:
Employee.find_by_email #current_user.email
As Mori's answer states, you probably didn't intent do use #current_user.email as a hash key into params. I think you're trying to look up the employee record for the current user by email (not by an email submitted as a parameter), like so (also avoiding deprecated find_by_* helpers):
#employee = Employee.find_by(email: #current_user.email)
I don't think you want to try to do Employee.find(#current_user.id) - that's just going to look up the Employee whose id matches the current_user's id - unless Employee and User use the same table that's not going to be meaningful
Why not just find by the ID? find_by_* are old.
#employee = Employee.find(#current_user.id)
I'm having trouble parsing through a hash and then saving certain parts to my database. I'm able to iterate through it to get to the information that I need. My problem is updating the record in my database. I'm trying to update an existing record in my database based on if the country code for each country matches the country code in the XML parse.
In my controller I have:
class CountriesController < ApplicationController
def index
#countries = Country.all
travel_alerts = request_data('http://travel.state.gov/_res/rss/TAs.xml')
travel_warnings = request_data('http://travel.state.gov/_res/rss/TWs.xml')
# Sets warnings
warnings_array = travel_warnings["rss"]["channel"]["item"]
warnings_array.each do |warning|
#country = Country.find_by(code: warning["identifier"].strip)
#country.update(title: warning["title"],
description: warning["description"])
end
end
end
...
I've tried using .update and .save, but neither works. When I try update I get:
undefined method `update' for nil:NilClass
Does the update method need to be explicitly defined in the Country model? If so, what's the best way to have access to the parsed information since that's being done in the controller?
It raises an error, because Country by given code was not found, then find_by returns nil, on which update method does not exist.
Instead of find_by executrun find_by! - you should get ActiveRecord::RecordNotFound error
If it is expected some countries do not exist put your update statement within if block
if #country
#country.update ...
end
With the koala gem I am trying to count checkins for a page. I am using rails.
In my user.rb I have a method for getting a new connection to the Facebook graph:
class User < ActiveRecord::Base
def facebook
#facebook ||= Koala::Facebook::API.new(oauth_token)
end
end
In my school.rb I have a method for counting the checkins:
class school < ActiveRecord::Base
def count_checkins(name)
checkins = #facebook.fql_query("SELECT checkins FROM page WHERE name = #{name}")
end
end
And I am calling it from the view like this:
<%= #school.count_checkins(#school.name) %>
But I get the following error:
undefined method `fql_query' for nil:NilClass
Dont really understand why I get this error, any help would be wonderful.
It looks like you haven't actually created the #facebook object inside your School model. We'd need to see the rest of your school.rb file to know for sure. I'd suggest you create the object inside your School.initialize() method like so:
def initialize(oauth_token)
unless oauth_token.nil?
#facebook = Koala::facebook::API.new(oauth_token)
end
end
In order for this to work, you'll need to pass the desired oauth_token to your School.new() call. Then you'll have one #facebook object for each School.
Edit
After looking at the gist, I realized that you had actually intantiated a User object, and called the facebook method on that. That is actually the better way to do it. The problem is, you're using #current_user, which would have to be setup as a property of the school model. You probably meant to use the helper function current_user instead.
def count_checkins(name)
u = current_user
u.#facebook.fql_query("SELECT checkins FROM page WHERE name = #{name}")
end
Try that and see what happens. At the very least, you should get a different error message.
Edit 2
So, now I'm thinking the current_user function should be called in controller code, not model code. This is because the current user is something that doesn't really exist except as part of an active request. Therefore, we should take User u as a parameter to the count_checkins function like so:
def count_checkins(name, u)
u.facebook.fql_query("SELECT checkins FROM page WHERE name = #{name}")
end
You'll need to change the code where you call count_checkins() too:
count_checkins(name, current_user)
That should do it. Let's see!
I have a resource in my project that collects some information from a user. Basically it's a form that they fill out before they can access another area of the site. It then sets a cookie for a week, but if they come back it will look up their previous entry and keep their preferences tied to them (and will update any details as long as the email address matches).
Currently I have a Applicants controller that looks like this:
class ApplicantsController < ApplicationController
...
def create
#applicant = Applicant.find_or_initialize_by_email(params[:applicant])
if #applicant.new_record? ? #applicant.save : #applicant.update_attributes(params[:applicant])
set_cookie_and_redirect
else
render 'new'
end
end
def update
if #applicant.update_attributes(params[:applicant])
set_cookie_and_redirect
else
render 'new'
end
end
end
The set_cookie_and_redirect is a private method that just sets some cookies and redirects the user to a page. The code works, but it just feels dirty. It's essentially updating a record within the create method under the condition that it's not a new record. I'm also forced to have an update method in case an existing record comes back with a validation error--the form helper will then switch the form over to sending to the update method.
So to my point... is there a more appropriate way to push the update_attributes call in the create method to the update method? Or better put, is there a better way to respect the RESTful methods in isolating the create and update functionality?
UPDATE: I wanted to be a little more specific too. If the user has filled this form out before it will set a cookie so they don't have to fill it out again for seven days. However after seven days the cookie is expired and they see the form again. The controller doesn't know if the user is new or existing until they add user input into the form which is then compared based on the email address.
Thanks in advance! I definitely look forward to anyone's thoughts on this.
The create method should only create, and the update method should only update. Let Rails decide which is going to happen based on what is inside of #applicant when the form is rendered - It essentially does what you're doing: Checks if the record is new or not, and sends it to update/create accordingly. Example:
def applicant
#applicant = Applicant.find_or_initialize_by_email(cookies[:email])
# renders applicant.html.erb form
end
<%= form_for #applicant do |f| %>
# ... fields ...
<% end %>
def create
#applicant = Applicant.new(params[:applicant])
#applicant.save
# .. etc.
end
def update
#applicant = Applicant.find_by_email(cookies[:email])
#applicant.update_attributes(params[:applicant])
# ... etc.
end
Rails will send the request to the correct action based on the new_record? status of the Applicant object.