How to use parameters value from public_activity gem (Rails)? - ruby-on-rails

I am building a Rails app. And in my app, there are Projects where users can "Follow". When a user follows one of the pages, he/she will get updates if somebody uploads/creates a folder/file.
Below is the screenshot when somebody just created a new folder:
And below is the code for "Create" action in my Folder controller:
def create
#folder = current_user.folders.where(project_id: params[:project_id]).create(folder_params)
respond_to do |format|
if #folder.save
#folder.create_activity :create, owner: current_user, :params => {
:project_id => proc {|controller, project| #folder.project.id},
:project_name => proc {|controller, project| #folder.project.name},
}
format.html { redirect_to #folder.project, notice: 'Folder was successfully created.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { render :new }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
As you can see :project_id and :project_name are the parameters for the public_activity when a new folder being created.
And below is the screenshot on how this parameters value looks like in the database after they were saved:
QUESTION:
So my question is, how do i use this parameters values in my activities_controller?
Here is the code for my activities controller right now:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc").where(owner_id: current_user.following_users, owner_type: "User")
end
end
Instead of using "owner_id:", I want to use the "project_id" value from parameters column. So how can i do this?
Thank you very much in advanced! :)

The parameters field contains a simple yaml dump, so not really easy to search efficiently.
A simple solution would be to use LIKE operator, for instance
PublicActivity::Activity.where("parameters LIKE '%project_id: #{#project.id}%'")
You might want to consider to add custom fields instead.

Thanks for the answer, but I got a better solution than using the parameters value or custom field.
Here is how my activities_controller looks like right now:
class ActivitiesController < ApplicationController
def index
activity_table = PublicActivity::Activity.arel_table
# We want to view all activity of folders related to projects we are follwing
folder_ids = Folder.where(project_id: current_user.following_projects.pluck(:id)).pluck(:id)
# Generate query for all activity related to folders we care about
folders_query = activity_table[:trackable_type].eq('Folder').and(
activity_table[:trackable_id].in(folder_ids)
)
# Generate query for all users that we follow
users_query = activity_table[:owner_id].in(current_user.following_users.pluck(:id))
activity_query = folders_query.or(users_query)
#activities = PublicActivity::Activity.where(activity_query)
end
end
By using this way, I could easily combine the activities from the "Users" and also from the "Projects" that the user follows.
You can modify it to add any other activities such as from the "Comments" or "Voting".
Hope this will help other people out there that are using public_activity gem! :)

Related

nested form rails 4 save existing record on create

I am struggling to get this working. I have three models
Student
Classroomattnd
Classroom
Using the has_many :through relationship. All my relationships are defined correctly and I have setup the nested form using the accepts_nested_attributes.
So when creating a new student I want to select from a list of classrooms instead of creating a new classroom. The form part also works fine the part I am not getting is when I create the student it complains about the following error.
Couldn't find Classrooom with ID=3 for Student with ID=
I have searched around for few days now but can not get the answer I need to get this working.
def new
#student = Student.new
#student.classrooms.build
end
def edit
end
def create
#student = Student.new(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice: 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
Can someone help here, someone must of face this issue before?
Also in the rails console when I run the following it works:
classroom = Classroom.last
student = Student.create(name: 'Dave', classrooms:[classroom])
Your parameter handling isn't supporting nesting. You can look at request parameters in your server log or inspect the fieldnames of your generated form to be sure of your target. It's going to be something along the lines of
def student_params
params.require(:student).permit(:student => [:name, :classroom => [:id, :name]])
end
Or maybe as below. In this second case I'm not assuming everything in the form is nested under a student container. Also note the switch from classroom to classroom_attributes which is a change I have sometimes needed to make even though the form above is what the docs indicate.
def student_params
params.require(:name).permit(:classroom_attributes => [:id, :name])
end
Hopefully that gives you a notion of how to tailor your parameter definition to what your form is generating. Also note your error messages give you indication of what part of your definition is failing, eg the missing Student id in the error you quote.

:id => "info" error rails wicked forms when retrieving params

I'm new to wicked form and I was following the railcast episode on wicked forms but I keep receiving this error "Couldn't find Company with 'id'=info". So I know that the problem is clearly in my controllers somewhere. I know it's something super simple that I'm just racking my brain on so I know you guys will be a giant help. Here is the code, any and all help appreciated!
Code for companies Controller:
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
#object = #company.id
format.html { redirect_to(company_steps_path(#company)) }
format.json { render :show, status: :created, location: #company }
else
format.html { render :new }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
Code for company_steps Controller:
class CompanyStepsController < ApplicationController
include Wicked::Wizard
steps :info, :address, :quote
def show
#company = Company.find(params[:id])
render_wizard
end
def update
#company = Company.where(id: params[:id])
#company.attributes = params[:company]
render_wizard #company
end
end
When you use #find and the record is not found ActiveRecord raise a ActiveRecord::RecordNotFound with a message like "Couldn't find Company with id='somevalue'".
I assume your id column is of type integer and you pass a string.
In your #show method params[:id] == 'info'.
Check your link_to, redirect_to and routes.
At some point you generate this url http://localhost:3000/company_steps/info (probably in a view).
You do a GET request on it, which match GET "/company_steps/:id" company_steps#show.
The method #show is call in the controller CompanyStepsController with params[:id] == 'info'.
As we see previously you get a ActiveRecord::RecordNotFound exception because ActiveRecord can't find the record with a id 'info'.
The error is raise in your controller, but the problem is probably in your views or in a redirect. You need a id and you pass a string.
EDIT: as discussed in comments
Ok params[:id] == 'info' is generated by wicked.
They use id to control the flow of steps.
You need to use nested routes to have rails generate something like params[:company_id].
resources :companies do
resources :steps, controller: 'companies/steps'
end
So rake routes should give you:
/companies/:company_id/steps/:id
in the controller
params[:company_id] == 42
params[:id] == 'info'
https://github.com/schneems/wicked/wiki/Building-Partial-Objects-Step-by-Step

Rails calling create method from same controller instance variable

I have a few hours with something that is probably very easy.
I have a nested model
resources :grades do
resources :students
end
So I defined
before_action :set_grade, except: [:mass_input]
to my students_controller
def set_grade
#grade = Grade.find(params[:grade_id])
end
I'm very good with this, the problem is that now I'm using another action that takes :grade_id from another source, so I cant use set_grade, instead I'm passing the id with javascript. Works.
My problem appears here, when I try to call to create method, I'm probably doing it wrong ..
def mass_input
#grade = Grade.find(#data['grade'])
#data = JSON.parse(params[:form_data])
#is this create way ok or I'm overriding???
Student.create(:rut => #data['mass_students'][1][0], :nombre => #data['mass_students'][1][1], :apellido => #data['mass_students'][1][2])
end
This is my create action
def create
#student = Student.new(student_params)
#grade.students << #student
respond_to do |format|
if #student.save
format.html { redirect_to school_grade_path(#grade.school,#grade), notice: 'Alumno creado con éxito.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
By this way code works but this line is not working
#grade.students << #student
#grade is not passing from mass_input to create. I think I'm not calling create properly but I cant find how to do it , because is not redirecting neither
My mass_input action is working by this way
def mass_input
#grade = Grade.find(#data['grade'])
#data = JSON.parse(params[:form_data])
Student.create(:rut => #data['mass_students'][1][0], :nombre => #data['mass_students'][1][1], :apellido => #data['mass_students'][1][2])
grade.students << student
respond_to do |format|
if student.save
format.html { redirect_to school_grade_path(grade.school,grade), notice: 'Alumno creado con éxito.' }
format.json { render :show, status: :created, location: student }
else
format.html { render :new }
format.json { render json: student.errors, status: :unprocessable_entity }
end
end
end
but I think is AWFUL, I must use my own create action
Thanks!!
Oh... From my point of view you are doing smth strange... The fast solution for your issue would be smth like this:
1) Rewrite before action in a new way:
before_action :set_grade
And method set_grade:
def set_grade
#grade = Grade.find(params[:grade_id].presence || #data['grade'])
end
2) Set method for student params
def student_params
data = JSON.parse(params[:form_data])['mass_students']
#Transform data to be student params. For ex:
data.map{|_key, info| {:rut => info[0], :nombre => info[1], :apellido => info[2]}}
end
3) Rewrite mass_input method
def mass_input
respond_to do |format|
if (#students = #grade.students.create(student_params).all?(&:persisted?)
#some actions when everything is great.
else
#some actions if not of them valid (maybe redirect & show info about not created students)
end
end
end
But you should definetly read more rails guides... http://guides.rubyonrails.org/
Sorry, I couldn't comment it. So I can just post a reply, it is not an complete answer though. In the student controller
Try to use
#student = #grade.students.new
or
#student = Student.new
#student.grade = #grade or #student.grade_id = params[:grade_id]
So when you do #student.save, you won't need to do the line below, and it will still work
#grade.students << #student
Ruby on rails has conventions you should follow to simplify lots of things. The first thing I see here is that in your def mass_input, you are using
Student.create(...)
The method create, as it says, creates an object but also saves it into database. So you should have new instead of create because new does not save it to database, just instantiates it:
#student = Student.new
...inside def mass_input, and by default the submit action in your view will take your object to the create method (if the object is new it goes to create, other way it goes to update, thanks to Rails). For this you could take a look at http://guides.rubyonrails.org/action_controller_overview.html
About the line #grade.students << #student, I assume you are intending to add the newly created student to his grade. See this example of usage of nested resources when trying to create, edit or destroy http://railscasts.com/episodes/139-nested-resources. In any case, nested resources implies this:
class Grade < ActiveRecord::Base
has_many :student
end
class Student < ActiveRecord::Base
belongs_to :grade
end
So, in your model Student you should have a column to store the Grade of that student. And then in your params you should receive the actual grade and store it in the grade_id inside your #student.
If something is not clear, I suggest you to take a look at the nested resources guide http://guides.rubyonrails.org/routing.html#nested-resources
As a commentary, << is used to add "things" to the end of an array, i.e. if you want to quickly store in an array some info you use:
array = []
Student.all.each do |s|
array << s.name
end
It will store in the array all the names of your students. Obviously there is a simpler way to do this by doing this:
Student.pluck(:name)

Rails: best_in_place collection issue

My app runs on two different database, and I use the application logic to work on them.
I have the User model on an external db and I only records the id on my default_role class.
So in the index template I fetch the accounts from remote, and for each of them I have to query my table to print some immutable information and I want to give the possibility to change role in my table
Index information = remote tables information (name surname ecc) + my table information (role)
Using best_in_place to edit the role_id field of my users.
The problem is my index cycle #operators which comes from outside buy I need to change role which is on my side!
- #operators.each do |ope| #cycle users
%tr
%td
- user = User.find_by_bay_id(ope.account_id)
- df = DefaultRole.find_by_operator_id(user.id)
= best_in_place [:admin, df], :role_id, :type => :select, :collection => [[1, 'admin'], [2, 'coordinator'], [3, 'operator'], [4, 'base']]
and my update in controller:
respond_to :html, :json
def index
#operators = some logic from model where I get all the users
end
def update
#df = DefaultRole.find(params[:id])
#df.update_attributes(params[:default_role])
respond_with [:admin, #df]
end
But it didn't even call my update method in the controller.
It normally checks the collection tag, allows me to change it but it doesn't allow me to submit.
What am I doing wrong?
EDIT
My browser doesn't catch any request.
Best_in_place gem uses JSON calls to update the content . In this case you should have respond_to json statement in your controller , something like this :
def update
#df = DefaultRole.find(params[:id])
respond_to do |format|
if #df.update_attributes(params[:default_role])
format.html { redirect_to root_path, notice: 'Role was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #df.errors, status: :unprocessable_entity }
end
end
I find it strange to include variable specifications in your view , they belong to the controller (- user = User.find_by_bay_id(ope.account_id)
- df = DefaultRole.find_by_operator_id(user.id) .
I finally found the error.
https://github.com/bernat/best_in_place/issues/217
It was a Jquery issue on that version of best_in_place. Running:
bundle update
and restarting the server solve the problem, thanks everyone

Recommendations for constructing RESTful resources for avatar selection scenario in rails

We have a requirement where a user needs to select their avatar for their profile. On the edit profile page, the user clicks on a Change Picture link which takes them to another page and gives them with two links to get their photo from facebook or gravatar. There is also a preview of the image shown on this page, as well as a save button. The controller for this page is AvatarsController. I have edit and update actions, as well as custom GET actions for facebook and gravatar, so that the route looks like avatar/facebook, and avatar/gravatar. These actions simply query the respective services and create a new avatar model containing the url for the photo. When the user clicks save, the update action is called and the avatar model is saved with the profile. The page is delivered by the edit template, as by default, when a user is created, an empty avatar is also created.
The Profile model (using mongoid) essentially looks like:
def Profile
embeds_one :avatar
end
and the avatar model looks like:
def Avatar
embedded_in :profile
end
The route looks like:
resource :avatar, only: [:edit, :update] do
member do
get 'facebook'
get 'gravatar'
end
end
The controller looks like:
class AvatarsController < ApplicationController
def facebook
url = AvatarServices.facebook(current_user, params[:code])
respond_to do |format|
unless url
format.json { head :no_content }
else
#avatar = Avatar.new({:url => url, :source => "Facebook"})
#avatar.member_profile = current_user.member_profile
format.html { render :edit }
format.json { render json: #avatar }
end
end
end
def gravatar
respond_to do |format|
url = AvatarServices.gravatar(current_user)
unless url
format.json { head :no_content }
else
#avatar = Avatar.new({:url => url, :source => "Gravatar"})
#avatar.member_profile = current_user.member_profile
format.html { render :edit }
format.json { render json: #avatar }
end
end
end
def edit
#avatar = current_user.member_profile.avatar
end
def update
#avatar = current_user.member_profile.avatar
respond_to do |format|
if #avatar.update_attributes(params[:avatar])
format.html { redirect_to edit_member_profile_path }
format.json { head :no_content }
else
format.html
format.json { render json: #avatar.errors }
end
end
end
end
This works, but being fairly new to rails, I'm wondering if rails experts would have set up the 'facebook' and 'gravatar' resources differently, perhaps in a more RESTful manner?
Well, the subfolder is putting the facebook and gravatar controllers into a common namespace. You could use nested routes,
resource :avatar, only: [:edit, :update] do
resource :facebook
resource :gravatar
end
This will route to a FacebooksController and a GravatarsController.
This is kind of what you were thinking anyway, and you won't need a record id for a facebook or gravatar record.
Could you add your controller code? I'm interested to see how you have your actions setup.
If you want to keep things restful, it might just be a matter of creating a controller subfolder for avatars, and created subsequent controllers for gravatar & facebook. You can do this just using a generator
rails g controller avatars/facebook
rails g controller avatars/gravatar

Resources