Troublesome Wice::WiceGridArgumentError - ruby-on-rails-3.1

I am working on a Rails 3.1.1 app that is using WICE_GRID and I am stuck on this error.
I want to show a grid of Roles on the User show page. I am setting up the data in the controller like this.
User and Role are related by has_many through user_role.
def show
#user = User.find(params[:id])
#roles = initialize_grid(#user.roles)
end
When I run the site I get this error
Wice::WiceGridArgumentError in UsersController#show
WiceGrid: ActiveRecord model class (second argument) must be a Class derived from ActiveRecord::Base
The error is pointing to #roles = init.... line. initialize_grid does take a record arguent but that is a hash of options, not an activerecord model collection.
When I run the code in the console I see that #user.roles is
[#<Role id: 1, title: "Role1>, #<Role id: 2, title: "Role2">]
Looks like an ActiveRecord collection to me.
Any help gratefully accepted!

initialize_grid takes a class. You're passing in an array of objects. It appears you want to display a user's roles in the grid. You want something like this:
def show
#user = User.find(params[:id])
#roles = initialize_grid(Role, :conditions => ['user_id = ?', #user.id])
end
However, I'm guessing your roles table doesn't have user_id in it. You likely have a mapping table called user_roles. In which case, you will want to refactor the code above. Try just running this code instead to make sure you can view Roles in a grid (unscoped).
def show
#user = User.find(params[:id])
#roles = initialize_grid(Role)
end

Related

Ruby on Rails DB entry in a model (RoR 3)

Skip to EDIT2 which works
There is:
Project (has_many :group_permissions)
GroupPermission (belongs_to :project)
I have a form where you can create a new project. A project has several attributes like name, status etc. and now important: iit. iit is selectable with radio buttons: yes or no.
What I want:
If someone selects yes on iit in the Project form, there should be a new record in GroupPermission. So in EVERY project where iit= 1 there should be a certain GroupPermisson.
Can I make / check this in the GroupPermission model? Like if
class GroupPermission < ActiveRecord::Base
if Project.where(iit: 1)
make me a record for each project
end
Can I even make database entries in the model like so?
Is this the right way?
EDIT1:
In the Project controller I added:
if params[:iit] = 1
record = GroupPermission.new(cn: 'ccc-ml', project_id: params[:id])
record.save
end
It then adds a new record in GroupPermissions. But I need the :id of the project. How can I access the id of the project which is about to be saved?
EDIT2
In the Project Controller
after_filter :iit_test, :only => [:create]
...
private
def iit_test
if #trial.iit == 1
record = GroupPermission.new(cn: 'ccc-ml', project_id: #project.id, name: 'CATEGORY_3')
record.save
end
end
EDIT2 works fine. I just have to check it with update etc.
Thank you in advance.
the EDIT2 will only work for apis hitting the controller and not when you add a project via rails console, use in tests etc.
Also this :iit_test will not correctly work for update action as you are creating a new GroupPermission everytime. (GroupPermission may already exists for this project)
You should probably add a callback after_save in the project model and handle adding of a new GroupPermission there.
Write a before action in Project controller like below
def find_project
#project = Project.find_by(id: params[:id])
end
by calling above method in before action you will get the instance of the Project.
Hence you can create the Group Permission by
def create_group_permission
#project.group_permissions.create(cn: 'ccc-ml')
end
The above will create a GroupPermission record with a project id which was found in before action.
Instead of having a method in your projects_controller, you can move the logic to a seperate service. That will make your code easy to test etc..
Something like..
class ProjectsController < ApplicationController
def create
#project = ProjectService.create(project_params)
# rest of your controller code
end
end
#app/services
class ProjectService
def self.create(project_params)
project = Project.new(project_params)
if project.save && project.iit == 1
GroupPermission.create(cn: 'ccc-ml', project_id: project.id, name: 'CATEGORY_3')
end
project
end
end

Getting Sequel associations through Sinatra

I'm trying to return json-formatted data from my Sinatra REST API. I currently have a bunch of associations set up, but I'm having trouble getting the views I want from my API despite getting them easily in Ruby.
For example, from my tables:
DB.create_table?(:calendars) do
primary_key :id
end
DB.create_table?(:schedules) do
primary_key :id
foreign_key :resource_id, :resources
foreign_key :task_id, :tasks
foreign_key :calendar_id, :calendars
end
In Ruby, I'm able to run a block like this and display all the info I need through my associations:
Calendar.each do |c|
c.schedules.each do |s|
puts "RESOURCE ##{s.resource_id}"
s.tasks.each do |t|
p t
end
puts
end
end
the c.schedules call works because my calendar model contains a one_to_many :schedules association.
Now, I'm wondering how this translates to my Sinatra API. In my simple GET route, I've tried many variations trying to get the schedules associated with a calendar, and convert it to JSON:
get '/calendars' do
c = DB[:calendar].first
c.schedules.to_json
content_type :json
end
... but I'll end up with an error like undefined method 'schedules' for {:id=>1}:Hash
So it looks like it's returning a hash here, but I've tried a bunch of stuff and haven't figured out how I'm supposed to work with my associations in Sinatra. How can I do this?
Thanks!
The reason your first block works but the second doesn't is because in the first case, you're using a Sequel model instance of class Calendar, whereas in the second case you're using a Sequel dataset.
When you iterate over Calendar.each do |c|, the c variable gets populated with an instance of a Calendar class Sequel model object. This object has relationship methods defined (one_to_many) and you're able to query schedules and run other model methods on it.
However, c = DB[:calendar].first gets you a Sequel dataset. This object is different than a model instance, it returns a standard Ruby hash (or an array of hashes).
You can change your 2nd block to use a model instead and it will get the result you want:
get '/calendars' do
c = Calendar.first # <=== CHANGE FROM DATASET TO MODEL
c.schedules.to_json
content_type :json
end

Ruby on Rails: Getting a route with Devise

TL;DR How can I achieve this to always return routes with Devise User model ID in custom controllers (i.e. redirecting to localhost:3000/profiles/504026426) with Mongoid?
I have a project that has a social profile controller that returns of a user id with Devise but it will always complain that Mongoid needs a valid ID number in order to work with this route: localhost:3000/profiles/.
# Let's say I want to return a route with id (Devise) without having
# Rails to complain that Mongoid needs to a id of some number.
# So, I have controller containing profiles in the files.
# It goes like..
class ProfilesController < ApplicationController
before_filter :authenticate_user!
# GET /profile/
def index
#user = User.find(params[:id])
end
# .. Snipped for brevity.
end
Is this the right way to do it?
Firstly, the 'params[:id]' you're trying to find the user by won't work in the index view, because you're not passing in any parameter via the url ('profiles/:id' or: localhost:3000/profiles/504026426). If you want to store a user to be available in the index view, use sessions and the current user helper method. See here.
If you want your GET method to work with the 'params[:id]' it would look like:
get 'profile/:id' => 'profiles#show'
make sure it matches a show function in your controller
def show
# this would work with: localhost:3000/profiles/504026426
#user = User.find(params[:id])
end

Caching active record associations with fresh_when

What's the best way to cache ActiveRecord associations? Here's what I am trying to do in the controller:
def all_posts
#posts = User.find(params[:id]).posts
fresh_when #posts
end
Whenever a new post is added to the user model I need to clear the cache.
You're solution works perfect.
In case you are just adding posts there is a more performant solution: You'll have to had a touch: true to the belongs_to :user part of your Post model. ActiveRecord will touch the User object every time a post gets changed and a new post gets created. When you have that implemented you can use this controller code:
def all_posts
user = User.find(params[:id])
#posts = user.posts
fresh_when user
end
It is much faster to generate a cache key from one user than from many posts.
Have a look at http://www.xyzpub.com/en/ruby-on-rails/3.2/caching.html to get an introduction to caching in Rails.

Rails Active Record: Calling Build Method Should Not Save To Database Before Calling Save Method

I have a simple user model
class User < ActiveRecord::Base
has_one :user_profile
end
And a simple user_profile model
class UserProfile < ActiveRecord::Base
belongs_to :user
end
The issue is when I call the following build method, without calling the save method, I end up with a new record in the database (if it passes validation)
class UserProfilesController < ApplicationController
def create
#current_user = login_from_session
#user_profile = current_user.build_user_profile(params[:user_profile])
##user_profile.save (even with this line commented out, it still save a new db record)
redirect_to new_user_profile_path
end
Anyyyyyy one have anyyy idea what's going on.
The definition of this method says the following but it's still saving for me
build_association(attributes = {})
Returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key, but has not yet been saved.
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one
Ok, I'm sure experienced vets already know this, but as a rookie I had to figure it out the long way...let me see if I can explain this without screwing it up
Although I was not directly saving the user_profile object, I noticed in my logs that something was updating the user model's last_activity_time (and the user_profile model) each time I submitted the form (the user model's last_activity date was also updated when the logged in user did various other things too - I later realized this was set in the Sorcery gem configuration).
Per http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
AutosaveAssociation is a module that takes care of automatically saving associated records when their parent is saved. In my case, the user mode is the parent and the scenario they provide below mirrors my experience.
class Post
has_one :author, :autosave => true
end
post = Post.find(1)
post.title # => "The current global position of migrating ducks"
post.author.name # => "alloy"
post.title = "On the migration of ducks"
post.author.name = "Eloy Duran"
post.save
post.reload
post.title # => "On the migration of ducks"
post.author.name # => "Eloy Duran"
The following resolutions resolved my problem
1. Stopping Sorcery (config setting) from updating the users last_activity_time (for every action)
or
2. Passing an ':autosave => false' option when I set the association in the user model as follows
class User < ActiveRecord::Base
has_one :user_profile, :autosave => false
end

Resources